Issue
In existing code, I've come across type parameter declarations like this: <Param extends {}>.
My question is, what is the meaning of the extends {} part? How does it differ from simply <Param>?
Example:
type Fold<S extends {}, D extends {}> = {
folder: ...
}
Solution
{} vs unknown constraint
If you write <S>, S is unconstrained - it behaves like <S extends unknown> (TS 3.5+).
{} type can take every value (incl. primitives), except null or undefined with strictNullChecks.
unknown is more or less {} | null | undefined, making {} a more narrow subtype:
type FoldImplicit<S> = S
type FoldObject<S extends {}> = S
type T1 = FoldImplicit<"foo"> // ✅
type T2 = FoldImplicit<undefined> // ✅
type T3 = FoldObject<"foo"> // ✅
type T4 = FoldObject<undefined> // ❌ - `undefined` not in `{}` (strictNullChecks)
// compiles with `strictNullChecks` disabled
// - null and undefined now belong to every type.
Where do I see these constructs?
The most often encountered case is probably with React generic components:
// help compiler to distinguish JSX tag from generic component declaration
const Comp = <T extends {}>(props: { foo: T }) => <div>...</div>
To match implicit constraints more closely, you can write <T extends unknown> or just <T,> (note the comma). Before TS 3.5, the implicit constraint has been {}.
With extends {}, you can also take away undefined or null as possible inputs. But in my opinion a) it makes code unnecessarily verbose b) you better find a more narrow constraint for stronger types.
Answered By - ford04
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.