1

I have a type with some possibly undefined fields

type Foo = { 
  a: string | undefined
  b: string
  c: string | undefined
}

I want the same type, but declaring that none of the fields are undefined

type Bar = { 
  a: string
  b: string
  c: string
}

I'd like a way to derive Bar from Foo, so that I don't have to manually create Bar and update it when Foo changes. Something like this

type Bar = NoPropertiesUndefined<Foo>

Is there any generic like this built into Typescript?

A note on usecase - I'm using this when I get the type Foo as an input, then validate it to check no fields are undefined, then pass to another function for further processing. I'd like that other function to take a Bar argument, and have the validator return a Bar or throw, to ensure I've validated the Foo in a typesafe way. The Foo types can even be dynamically created themselves using ReturnType - so even the cumbersome nature of manually defining Bar aside, in some cases it's not even possible.

4

3 回答 3

4

The NoPropertiesUndefined generic from the question can be implemented like this

type NoPropertiesUndefined<T> = { [P in keyof T]: NonNullable<T[P]> }

You use it like:

type Bar = NoPropertiesUndefined<Foo>

Bar then has all the same fields as Foo, just none of them can be undefined.



I'll accept my own answer as it directly solves the exact problem I had, but I came to this solution via the answer from Yoni Gibbs, which mentions the related Required built in generic from which I got the inspiration for the above implementation. Please upvote that answer if you find this one useful!

于 2019-08-14T14:24:18.770 回答
1

Do you need to declare your type as above, or could you slightly change it to this instead:

type Foo = { 
  a?: string
  b: string
  c?: string
}

If you can do that then the built-in Required generic will do what you want, I think:

type NoUndefinedFoo = Required<Foo>

See here for details.

Here's how that generic type is defined:

type Required<T> = { [P in keyof T]-?: T[P] };

i.e. it removes the ? from every property of the T you pass into Required.

于 2019-08-14T14:11:29.487 回答
0
type Foo = { 
  a: string
  b: string
  c: string
}

None of those properties can be undefined - if you've enabled strict null checks in your TSConfig.

In strict null checking mode, the null and undefined values are not in the domain of every type and are only assignable to themselves and any (the one exception being that undefined is also assignable to void).

Also, I think you're looking for this...

type NonNullable<T> = T extends null ? never : T
// Exclude null and undefined from T

Usage:

type Bar = NonNullable<Foo>;
于 2019-08-14T13:27:55.637 回答