2

I have the following code:

type AZ = 'a'|'b'|'c'|'d'| ... |'z'; // union of many types

type Mapping = {
  [K in AZ]: string;
}

const obj: Mapping = { // error, missing properties 'c', 'd', etc.
  a: '',
  b: ''
};

This lets me constrain props of obj to only those matching the union, but it forces me to list them all. If I do this instead:

type Mapping = {
  [K in AZ]?: string;
}

Now I don't have to supply every prop, but the resulting prop types contain undefined. How can I express that I want to only supply some keys from AZ, but if they are supplied, they should not be undefined? In other words, I want:

const obj: Mapping = { // ok
  a: '',  // checks 'a' as string
  b: ''   // checks 'b' as string
  bad: '' // error 'bad' not in AZ
  // no additional props needed
};

... without having to use an assertion like obj[prop]!.

PS: is this related to https://github.com/microsoft/TypeScript/issues/13195 ?

  • 2
    Pretty sure this isn't possible, and not sure why you'd want to do this. You're going to have to check if they're `undefined` somewhere. What happens when you make a function `fn(mapping: Mapping)`? The function won't know which ones are supplied or not. – Tur1ng Nov 12 '20 at 06:04
  • Yeah, I basically want props to be optional but not undefined. When setting the value it matches the union prop/string val, then there's no way it can actually be undefined since when getting I'm also matching by union prop. Undefined is actually unhelpful here because it conflates the prop being optional with the type of its value. – tswoes10895 Nov 12 '20 at 06:13
  • 1
    Closest I can think of is: `type Mapping = { [K in T]: string };` and using it like `const obj: Mapping<'a'|'b'> = {a: '', b: ''};` https://www.typescriptlang.org/play?#code/C4TwDgpgBAggWlAvFA5AQxQHxQIyygY3wBMUBuKAekqgFcA7ASwHt6pmAzKAWzXpCihIAZwBQoodACyaMGEb0A5gB4AKlAgAPYBHrFhsOAD4kUAN6ioUANoBpKAqiqAugC4ow4ACcFi0QF8ycWoAAWBhAFotSAJgKK8vZi9RAlZPDQSk9xk5X2V0fDxsDhQTZAsrNHcUFAAaSygcapQAoNFQ8KjNGLiITOTU+nS+xK8AJmzZeSV8jGw8MvMGqtQW-3FB4f6AZkncmYL50tMKqBWa+qsm1cuqSjDI6IhY+NGGnDRiZvr-IA – Tur1ng Nov 12 '20 at 06:20
  • Thank you, unfortunately the union is enormous and I can't specify prop names manually :(( – tswoes10895 Nov 12 '20 at 06:46
  • 1
    You can write a generic helper to build that type implicitly: `function mapping(x : Mapping): Mapping { return x; }`. Then `const obj = mapping({ a: '', b: '' });` – Phu Ngo Nov 12 '20 at 06:53

0 Answers0