我有以下“视觉测试”(又名,我只是使用vs-code来直观地检查是否存在之下的红色波浪线)。它的目的是确保我传入的泛型类型确实将被调用约束为substitute()
:
interface IJob {
jobId: string;
extraneous?: number;
}
/**
* Bear in mind these tests are just to visually identify in
* the editor that the generics are passing their types around
* correctly.
*/
describe("Typings → ", () => {
it.skip('setting <T> imposes structure on the substitutions that are allowed in', () => {
const wrongType = {
jobId: "1234",
extraneous: "foobar"
}
const nonExistantType = {
jobId: "1234",
noCanDo: true
}
const ruleAbidingJob = {
jobId: "1234"
}
const t = TypedTemplate.create<IJob>();
t.substitute(wrongType); // this should be failing in TS
t.substitute(nonExistantType); // this should be failing in TS
t.substitute(ruleAbidingJob); // this should be fine
});
});
似乎允许ruleAbidingJob
并正确识别wrongType
已将无关设置为字符串而非数字作为接口定义它。不幸的是,它允许使用nonExistantType
而不会出错。
如果有帮助,这是视觉效果:
还有一个屏幕截图,显示substitute
的预期类型确实是 IJob :
答案 0 :(得分:1)
Typescript将包含额外属性的类型(nonExistantType
的类型)视为IJob
的子类型,这就是允许调用的原因。您可以将函数参数类型视为函数需要工作的最小属性集,因此如果传入的参数具有更多属性,则函数应该不关心。
Typescript确实有一个feature,它将额外的属性标记为错误,但仅当对象文字直接分配给特定类型的变量/参数时。在您的情况下,您可以将对象文字直接传递给函数,也可以显式键入常量:
const nonExistantType :IJob = { // Error
jobId: "1234",
noCanDo: true
}
// OR
t.substitute({
jobId: "1234",
noCanDo: true // error
})
修改强>
我们还可以通过在typescript 2.8中使用条件类型来检查没有额外的属性,创建对象:
const wrongType = {
jobId: "1234",
extraneous: "foobar"
}
const nonExistantType = {
jobId: "1234",
noCanDo: true
}
const ruleAbidingJob = {
jobId: "1234"
}
type NoExtraProperties<TSource, TTarget> = Exclude<keyof TSource, keyof TTarget> extends never ? true : "Extra properties detected";
function ensueNothingExtra<TSource, TTarget>(source : TSource, validation: NoExtraProperties<TSource, TTarget>) :TTarget {
return source as any
}
const t = TypedTemplate.create<IJob>();
t.substitute(ensueNothingExtra(wrongType, true)); // this is an error
t.substitute(ensueNothingExtra(nonExistantType, true)); // this is also an error
t.substitute(ensueNothingExtra(ruleAbidingJob, true)); // this is ok