Issue
I thought that TypeScript
would complain when trying to read the property length
of what could be an array
or never
, and then, that I would need to narrow down the type with a type predicate. This is not the case. Why ? How could I change the types so TypeScript force me to check that I am not dealing with an empty object ?
// strictNullChecks = true
type Empty = Record<string, never>;
type NonEmpty = {
documents: Array<number>;
};
function isEmpty(x: Empty | NonEmpty): x is Empty {
return !("documents" in x);
}
const count = (x: Empty | NonEmpty) => {
// TypeScript does not complain about reading `length` property of `never`
// if (isEmpty(x)) {
// return 0;
// }
return x.documents.length;
};
Solution
Below is a step by step type destruction example:
type Empty = Record<string, never>;
type NonEmpty = {
documents: Array<number>;
};
function isEmpty(x: Empty | NonEmpty): x is Empty {
return !("documents" in x);
}
const count = (x: Empty | NonEmpty) => {
type D0 = typeof x.documents
type D1 = (Empty | NonEmpty)[`documents`]
type D2 = Empty[`documents`] | NonEmpty[`documents`]
type D3 = never | NonEmpty[`documents`]
type D4 = NonEmpty[`documents`]
type D5 = Array<number>
return x.documents.length; // x.documents is number[], that's why no error here
};
And below is the expected behaviour example that may fit your need:
type EmptyExpected = Record<string, undefined>;
const countExpected = (x: EmptyExpected | NonEmpty) => {
type D0 = typeof x.documents
type D1 = (EmptyExpected | NonEmpty)[`documents`]
type D2 = EmptyExpected[`documents`] | NonEmpty[`documents`]
type D3 = undefined | NonEmpty[`documents`]
type D4 = undefined | number[]
return x.documents.length; // x.documents is number[] | undefined, that's why it is an error here
};
Answered By - Edwin
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.