我找到了一种解决方法,但实际上解决方案并不完美:
interface MyType {
id: string;
value: number;
}
const myType: MyType = {
id: '',
value: 0
};
type ArrType<T> = Array<keyof T>;
function isMyTypeArr<T>(arg: any[]): arg is ArrType<T> {
return arg.length === Object.keys(myType).length;
}
function checkKeys<T>(arr: ArrType<T>): void {
if (isMyTypeArr(arr)) {
console.log(arr.length);
// some other stuff
}
}
checkKeys<MyType>(['id', 'x']); // TS error
checkKeys<MyType>(['id']); // no console because of Type Guard
checkKeys<MyType>(['id', 'value']); // SUCCESS: console logs '2'
这个想法是创建一个实现初始接口的简单对象。我们需要这个对象来获取它的密钥长度,以便在isMyTypeArr
Type Guard 中进行比较。Type Guard 只是比较数组的长度 - 如果它们具有相同的长度,则意味着您提供了所有属性。
编辑
添加了另一个类似(更通用)的解决方案 - 主要区别是:
- 使用带有实现初始接口的构造函数参数的类;
- 这个类有
length
属性(因为它基本上是一个构造函数)我们可以在我们的类型保护中使用它;
- 我们还必须将类名作为第二个参数传递,以获取它的构造函数参数长度。我们不能
T
为此使用泛型类型,因为编译后的 JS 已经删除了所有类型信息,我们不能T
用于我们的目的,查看这篇文章以获得更多详细信息
所以这是最终的解决方案:
interface IMyType {
id: string;
value: number;
}
class MyType implements IMyType {
constructor(public id: string = '', public value: number = 0) {}
}
type ArrType<T> = Array<keyof T>;
function isMyTypeArr<T>(arg: ArrType<T>, TClass: new () => T): arg is ArrType<T> {
return arg.length === TClass.length;
}
function checkKeys<T>(arr: ArrType<T>, TClass: new () => T): void {
if (isMyTypeArr<T>(arr, TClass)) {
console.log(arr.length);
// some other stuff
}
}
checkKeys<MyType>(['id', 'x'], MyType); // TS error
checkKeys<MyType>(['id'], MyType); // no console because of Type Guard
checkKeys<MyType>(['id', 'value'], MyType); // SUCCESS: console logs '2'
请注意,这些示例基于TypeScript 问题 13267
ps 还创建了两个示例的stackblitz 演示