interface Foo {
a: number;
b: string;
}
function augment<T>() {
return <A extends keyof T>(actions?: A[]) => {
const C = class {
// some code here that is irrelevant for my issue
};
return C as unknown as new () => InstanceType<typeof C> & Pick<T, A>;
};
}
const Class = augment<Foo>()(["a", "b"]);
const instance: InstanceType<typeof Class> = new Class();
// 👍 instance.a and instance.b are available, as expected
const Class2 = augment<Foo>()([]);
const instance2: InstanceType<typeof Class2> = new Class2();
// 👍 instance2.a and instance.b do no exist
const Class3 = augment<Foo>()();
const instance3: InstanceType<typeof Class3> = new Class3();
// 👎 instance3.a is available even if I didn't pass any actions :-(
在
augment
中,我使用actions
参数来推断A
类型。
它适用于
Foo
的任何属性,但是当我不通过某些操作时,就像推理类型推断出 A
是 keyof T
.
我知道我可以传递一个空数组,但我真的希望有可能不为我的函数传递任何操作,有没有办法做到这一点?
这是因为如果无法推断
A
,TypeScript 将默认使用其泛型约束类型。幸运的是,您可以通过提供默认值来覆盖此行为。如果因为没有为A
传递任何内容而无法推断出actions
,您可以默认为never
:
function augment<T>() {
return <A extends keyof T = never>(actions?: A[]) => {
// ~~~~~~~~ defaults to `never` if `A` cannot be inferred
const C = class extends EventEmitter {};
return C as unknown as new () => InstanceType<typeof C> & Pick<T, A>;
};
}
然后,在第三个例子中,你会得到错误,因为它现在正在使用
Pick<Foo, never>
:
const Class3 = augment<Foo>()();
const instance3: InstanceType<typeof Class3> = new Class3();
instance3.a; // error
instance3.b; // error