I have a container that can contain any value, but has helper methods in case it's an array. Behold:
class Container<T> {
constructor(public t: T) { }
push(o: T extends Array<infer R> ? R : never) {
if (this.t instanceof Array) {
this.t.push(o)
}
}
}
const c = new Container([1,2,3])
c.push(4)
We ought to have some type safety at runtime, and therefore we ought not to remove the instanceof
check.
But supposing that I already have other means of doing such type checking, so that this instanceof
is redundant.
In this case, is it possible to have TypeScript infer that this.t
is in fact an Array, within the body of push
, without any runtime check?
Perhaps by utilizing the fact that o
is already dependent on this guard, and potentially by narrowing o
?
You can use a factory with omitting push
(or any other props) if T
isn't an array:
class Container<T> {
constructor(public t: T) { }
static create<T>(t: T) {
return new Container(t) as T extends unknown[] ? Container<T> : Omit<Container<T>, 'push'>
}
push(this: T extends unknown[] ? this & {t: unknown[]} : never, o: T extends unknown[] ? T[number] : never) {
this.t.push(o)
}
}
const c = Container.create([1,2,3])
c.push(4)
const c2 = Container.create('string');
c2.push(5); // Property 'push' does not exist on type 'Omit<Container<string>, "push">'.(2339)