Checking if a value is valid for a union type

前端 未结 2 910
闹比i
闹比i 2020-12-04 03:36

Suppose I have this type defined in my app:

type PiiType = \'name\' | \'address\' | \'email\';

I u

相关标签:
2条回答
  • 2020-12-04 04:21

    The trick is to run the array through an identity function that infers an element type constrained by string. That will cause the compiler to infer a union of literal types:

    function asLiterals<T extends string>(arr: T[]): T[] { return arr; }
    const piiTypeValues = asLiterals(['name', 'address', 'email']);
    type PiiType = (typeof piiTypeValues)[number];
    

    There's another solution here but the above seems a bit simpler.

    0 讨论(0)
  • 2020-12-04 04:28

    While duplicating the union is not ideal we can use the compiler to validare that the union and the duplicated values are in sync. If you don't have control over the union this is the safest way to go (otherwise @Matt-McCutchen's solution is the better way to go)

    We can take advantage of mapped types and excess object literal properties check to create a function that will take an object with the same keys as the union. The values of the object don't matter we will just use the literal type 0

    type PiiType = 'name' | 'address' | 'email';
    
    function isValidBuilder<T extends string>(o: Record<T, 0>) {
      let values = Object.keys(o)
      return function (v: string): v is T {
        return values.indexOf(v) !== -1
      }
    }
    
    const isValidPii = isValidBuilder<PiiType>({
      name: 0,
      address: 0,
      email:0
    })
    
    // Error  missing key
    const isValidPii2 = isValidBuilder<PiiType>({
      name: 0,
      address: 0,
    
    })
    
    //error excess key
    const isValidPii4 = isValidBuilder<PiiType>({
      name: 0,
      address: 0,
      email: 0
      other:0
    })
    
    0 讨论(0)
提交回复
热议问题