Typescript中具有严格形状约束的泛型

时间:2018-07-24 10:30:22

标签: typescript

查看以下代码时:

type Test<T extends {a: number}> = ...doing something with keyof T...

Test<{a:1}> // ok
Test<{a:1, b:1}> // ok, but I want this to fail due to having 'b';

有什么方法可以使第一个还可以,但严格限制形状并不允许额外的属性,就可以使第二个不可以。

2 个答案:

答案 0 :(得分:2)

您不能直接使用它,但是可以通过使用条件类型来确保该类型如果具有额外的属性,则不会真正可用:

type Test<T extends { a: number }> = Exclude<keyof T, keyof { a: number }> extends never ?  T : "T must be exactly of type { a: number }";
let ok: Test<{ a: number }> = { a: 10 }; // ok
let nok: Test<{ a: number, b: number }> = { a: 1, b: 2 }// nok; Type '{ a: number; b: number; }' is not assignable to type '"T must be exactly of type { a: number }"'.

进一步的讨论

Typescript确实会在直接分配对象文字时检查额外的属性,因此这将是一个错误:

let a: { a: number } = { a: 1, b: 1 }; // error Object literal may only specify known properties...

但是如果类型兼容(即具有更多属性),则允许从其他来源进行赋值

let ab = { a: 1, b: 1 };
let a: { a: number } = ab // ok

上面的类型(或它的变体)可以帮助我们创建一个我们不想要多余属性且可以推断出泛型参数的函数:

function create<T extends { a: number }>(p: T & (Exclude<keyof T, keyof { a: number }> extends never ?  T : "T must be exactly of type { a: number }")) : T{

}
create({ a: 1, b: 1 }); //Type '{ a: number; b: number; }' is not assignable to type '"T must be exactly of type { a: number }"'.
create({ a: 1 }); //ok

答案 1 :(得分:0)

  

但严格限制形状并不允许额外的属性是第二种方法。

不适用于泛型。将每个T替换为其值,例如将function setTrigger() { ScriptApp.newTrigger("LiDCOcheck") .timeBased() .everyMinutes(1) .create(); } function LiDCOcheck() { var ss = SpreadsheetApp.getActiveSpreadsheet(); var ui = SpreadsheetApp.getUi(); var buttons = ui.ButtonSet.YES_NO; var bed = ss.getRange("C2").getValue(); var due = new Date(ss.getRange("D2").getValue()); var time = new Date(ss.getRange("A2").getValue()); if (+due.getHours() == +time.getHours()) { var lidco = ui.alert("It hsa been 24 hours since the LiDCO in Bed " + bed + " was calibrated. Is it still required?", buttons); if (lidco == ui.Button.YES) { ss.getRange("D2").setBackground('#ff9900');} else { ss.getRange("D2").setValue('Not Required')} } } 替换为type Test<T extends {a: number}> = T