先说几句:首先,无论何时编写IMyInterface,都需要指定类型参数。类似的东西
let obj = <IMyInterface> { // error
target: { name:"John", age: 100 },
to: { age: 200 }
}
总是会出错,因为您遗漏了类型参数。这将起作用:
let obj = <IMyInterface<{ age: number }>> {
target: { name:"John", age: 100 },
to: { age: 200 }
}
或者,更习惯于 TypeScript,您注释变量的类型而不是断言值的类型:
let obj: IMyInterface<{ age: number }> = {
target: { name:"John", age: 100 },
to: { age: 200 }
}
如果您对IMyInterface 的定义指定了default type parameter,则可以省略类型参数,但这不会按照您想要的方式工作,因为默认值始终相同,并且您想要更改的内容取决于to 属性的类型。
我的下一个问题是:您是否希望 P 仅用于检查您是否正确创建了 IMyInterface<T>?所以一旦你创建了一个有效的IMyInterface<T>,你就可以在使用它时立即忘记P?它看起来像它。在这种情况下,我要做的是将P 排除在IMyInterface<T> 的定义之外,而是使用辅助方法。您注意到一个方法可以帮助您键入检查,但您想要一个对象,对吧?好吧,辅助方法可以返回一个有效的IMyInterface<T>:
namespace HelperFunctionSolution {
// original definition
interface IMyInterface<T extends { [key: string]: number }> {
target: T;
to: T;
}
// helper method
function makeMyInterface<T extends { [key: string]: number }, P extends T>(
target: P,
to: T
): IMyInterface<T> {
return { target, to };
}
现在你可以使用你的辅助方法了:
const goodObj = makeMyInterface({ name: "John", age: 100 }, { age: 200 }) // okay
如果您检查goodObj,您会发现它是IMyInterface<{age: number}>。编译器会抱怨你想要的地方:
const badObj0 = makeMyInterface({}, { x: 30 }) // x is missing
const badObj1 = makeMyInterface({ name: "John", y: 1980 }, { x: 30 })
// complains about extra property but real problem is x
const badObj2 = makeMyInterface({ x: "20" }, { x: 30 }) // complains about string
const badObj3 = makeMyInterface({ name: "John", x: "20" }, { x: 30 })
// complains about extra property but real problem is x
现在你可以制作你想要的方法了:
class Hmm {
methodName<T extends { [key: string]: number }>(target: T, to: T) { /*impl*/ }
等等,这是你的定义,但我认为你希望它采用这样的对象:
realMethodName<T extends { [key: string]: number }>(
myInterface: IMyInterface<T>
) { /*impl*/ }
}
并使用它,确保使用辅助函数:
const hmm = new Hmm();
hmm.realMethodName(makeMyInterface({ name: "John", age: 20 }, { age: 30 })); // okay
}
您不能在其中使用对象字面量并保证类型检查,因为只有辅助函数关心P。所以这是一种方法,但您需要使用辅助函数。
另一种可能性是您在IMyInterface 定义中随身携带P 类型。这可能不是您想要的,但它具有理想的效果,您可以在 methodName 方法中使用字符串文字并且不需要辅助函数:
namespace TwoTypeParameterSolution {
interface IMyInterface<T extends { [key: string]: number }, P extends T> {
target: P;
to: T;
}
class Hmm {
realMethodName<T extends { [key: string]: number }, P extends T>(
myInterface: IMyInterface<T,P>
) { /*impl*/ }
}
const hmm = new Hmm();
hmm.realMethodName({target: { name: "John", age: 100 }, to: { age: 200 }}) // okay
hmm.realMethodName({target: {}, to: { x: 30 }}) // x is missing
hmm.realMethodName({target: { name: "John", y: 1980 }, to: { x: 30 }})
// complains about extra property but real problem is x
hmm.realMethodName({target: { x: "20" }, to: { x: 30 }}) // complains about string
hmm.realMethodName({target: { name: "John", x: "20" }, to: { x: 30 }})
// complains about extra property but real problem is x
hmm.realMethodName({ target: { name: "John", age: 20 }, to: { age: 30 } }); // okay
}
任何一种方式都应该适合你。希望有帮助;祝你好运!