我正在尝试通过TS实现以下目标:
let m: Extendable
m.add('one', 1)
// m now has '.one' field
m.add('two', 2)
// 'm' now has '.one' and '.two' fields
我熟悉通过以下方式在TS中返回扩展类型:
function extend<T, V>(obj: T, val: V): T & {extra: V} {
return {
...obj,
extra: val
}
}
现在,我的情况有两个问题:
1)对象m
在调用add()
后需要更新其类型,以反映新字段的添加
2)参数化了新字段的名称(例如,并非总是extra
)
第一个问题可能是通过使用类定义并以某种方式使用TypeThis
实用程序来重新调整类型来解决的,但是我找不到足够的文档来使用它。
欢迎任何帮助或指导。谢谢!
答案 0 :(得分:4)
TypeScript 3.7引入了assertion functions,可用于缩小传入参数甚至this
的类型。断言函数看起来像user-defined type guards,但是您在类型谓词之前添加了asserts
修饰符。这是将Extendable
作为声明方法的类来实现add()
的方法:
class Extendable {
add<K extends PropertyKey, V>(key: K, val: V): asserts this is Record<K, V> {
(this as unknown as Record<K, V>)[key] = val;
}
}
当您调用m.add(key, val)
时,编译器断言m
将具有一个属性,其键的类型为key
,而对应的值的类型为val
。使用方法如下:
const m: Extendable = new Extendable();
// ~~~~~~~~~~~~ <-- important annotation here!
m.add('one', 1)
m.add('two', 2)
console.log(m.one.toFixed(2)); // 1.00
console.log(m.two.toExponential(2)); // 2.00e+0
一切正常。调用m.add('one', 1)
后,可以引用m.one
,而不会出现编译器警告。
不幸的是,有一个fairly major caveat;断言函数只有在具有显式注释的类型时才起作用。根据{{3}},“存在此特定规则,因此对潜在断言调用的控制流分析不会循环触发进一步的分析。”
这意味着以下错误:
const oops = new Extendable(); // no annotation
oops.add("a", 123); // error!
//~~~~~~~~ <-- Assertions require every name in the call target to be declared with
// an explicit type annotation.
唯一的区别是,{em}推断为oops
的类型为Extendable
,而不是Extendable
为m
的{em {1}}是。而且,您在调用oops.add()
时遇到错误。根据您的用例,这可能没什么大不了的,也可能不是一件大事。
好的,希望能有所帮助;祝你好运!