[英]How to write an abstract typescript generic type?
给定以下类型
interface Base {
id: string;
}
interface A extends Base {
propA: string;
}
interface B extends Base {
propB: string;
}
我想表达一个具有以下约束的通用MyGeneric<T>
:
T
必须是 objectT
键必须是string
T
值必须是instanceOf Base
(类型为Base
或扩展 Base 的类型)
(3. T
值是否必须与Base
接口兼容,但已重新措辞以避免误解)
我试过了
interface MyConstraint {
[key: string]: Base
}
interface MyGeneric<T extends MyConstraint> {
data: T
}
但是在这种情况下,当用户想要使用它时,它有两个缺点:
interface userDefinedInterface1 {
a: A;
b: B;
}
function foo1(p: MyGeneric<userDefinedInterface1>):void {
//drawback 1: this throws TS2344:
//Type 'userDefinedInterface1' does not satisfy the constraint 'userDefinedInterface1'. //Index signature is missing in type 'userDefinedInterface1'.
}
//to solve drawback 1, the user has to extend MyConstraint
interface userDefinedInterface2 extends MyConstraint {
a: A;
b: B;
}
function foo2(p: MyGeneric<userDefinedInterface2>):void {
//drawback 2: here, ts considers every string property as valid because of [key: string]
console.log(p.data.arbitraryKey);//this is valid
}
有没有办法定义interface MyGeneric<T>
以尊重提到的 3 个约束而没有这两个缺点?
只有一个限制——如果你想添加额外的密钥,你必须指定它们。
interface Base {
id: string;
num: number;
}
interface A extends Base {
propA: string;
}
interface B extends Base {
propB: string;
}
type MyGeneric<T extends Base, K extends keyof any = never> = {
data: T & {
[key in K | keyof T]: key extends keyof T ? T[key] : string;
}
}
const test1: MyGeneric<B, 'test'> = {
data: {
id: '123',
num: 123,
propB: '123',
test: '123',
},
};
const test2: MyGeneric<B> = {
data: {
id: '123',
num: 123,
propB: '123',
test: '123', // fails, it has to be provided in current TS.
},
};
如果您只想依赖T
的键。
然后只需使用此版本:
type MyGeneric<T extends Base> = {
data: T & {
[key in keyof T]: key extends keyof Base ? Base[key] : string;
}
}
我认为这应该可以解决您的两个缺点:
type MyConstraint<T> = {
[K in keyof T]: T[K] extends Base ? T[K] : never;
};
interface MyGeneric<T extends MyConstraint<T>> {
data: T;
}
以低廉的价格使MyConstraint
通用。 如果你做了类似的事情,你的两个例子现在应该可以工作了,当然还有:
interface UserDefinedInterface3 {
a: A;
b: B;
c: string;
}
type Wrong = MyGeneric<UserDefinedInterface3>;
您会收到一条错误消息,指出属性c
的类型不兼容。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.