如何描述函数通过引用对对象进行变异



我有一个通过引用修改对象的函数:

function addProp(object, value) {
object.foo = value;
}

如何告诉TypeScriptobject值在调用addProp函数后更改了类型?我期待这样的代码:

interface WithProp<T> {
foo: T;
}
function addProp<T1 extends object, T2>(object: T1 mutatesTo (T1 & WithProp<T2>), value: T2) {
object.foo = value;
}
const obj = { bar: 'baz' };
obj.foo; // TS: error
addProp(obj, 123);
obj.foo; // TS: ok

类型系统并没有真正适应变量类型的变化。它确实使用控制流分析来缩小变量的类型,至少在某些代码块中是这样,但直到最近,还没有办法编写addProp()来触发这种基于控制流的缩小。

TypeScript 3.7引入了断言函数来表示不返回值但防止无效状态的函数。它们是非常新的,有一些奇怪的限制,所以请注意。

但是您现在可以做的是将addProp()表示为断言函数,它表示类型T1的输入现在被断言为更窄的类型T1 & WithProp<T2>。在这种情况下,如果输入不是那种类型,函数实现不是抛出错误,而是通过添加属性使成为那种类型。但类型系统都是一样的。不管怎样,它看起来是这样的:

function addProp<T1 extends object, T2>(
o: T1,
value: T2
): asserts o is T1 & WithProp<T2> {
(o as T1 & WithProp<T2>).foo = value;
}

然后它按照你想要的方式运行:

let obj = { bar: 'baz' };
obj.foo; // error! foo does not exist on {bar: string}
addProp(obj, 123);
obj.foo; // okay

请注意,这种缩小是控制流分析的结果,控制流分析会在分配时重置,因此您可能会惊讶于以下内容不起作用(请注意,我在上面放了let而不是const(:

// weirdness on reassignment
obj = { bar: "baz", foo: 1 }; // error! foo is extra

但这是我能最接近于代表类型系统中这种突变的一次。好吧,希望这能有所帮助;祝你好运

链接到代码

最新更新