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;
};
CodePudding user response:
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
};
CodePudding user response:
Never gets dropped from union types (e.g. 0 5 = 5).
type Test1 = never | string // string
Never overrides other types in intersection types. (e.g. 0 x 5 = 0)
type Test2 = never & string // never
Docs: https://www.typescriptlang.org/docs/handbook/2/narrowing.html#the-never-type