打字稿 - 逐步扩展对象的类型

Abs*_*thm 5 typescript typescript-generics

我正在尝试使用 TS 实现以下目标:

let m: Extendable
m.add('one', 1)
// m now has '.one' field
m.add('two', 2)
// 'm' now has '.one' and '.two' fields
Run Code Online (Sandbox Code Playgroud)

我熟悉通过以下方式在 TS 中返回扩展类型:

function extend<T, V>(obj: T, val: V): T & {extra: V} {
    return {
        ...obj,
        extra: val
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,在我的情况下有两个问题:

1) 对象madd()被调用后需要更新其类型以反映新字段的添加

2)新字段的名称被参数化(并不总是extra例如)

第一个问题可能会通过使用类定义并以某种方式使用TypeThis实用程序来重新调整类型来解决,但我无法找到足够的关于如何使用它的文档。

欢迎任何帮助或指导。谢谢!

jca*_*alz 5

TypeScript 3.7 引入了断言函数,可用于缩小传入参数的类型,甚至this. 断言函数看起来有点像用户定义的类型保护,但是你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;
    }
}
Run Code Online (Sandbox Code Playgroud)

当您调用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
Run Code Online (Sandbox Code Playgroud)

这一切都如您所愿。调用后m.add('one', 1),您可以在m.one没有编译器警告的情况下进行引用。

不幸的是,有一个相当重要的警告;断言函数仅在具有明确注释的类型时才有效。根据相关拉取请求,“存在此特定规则,因此潜在断言调用的控制流分析不会循环触发进一步分析。”

这意味着以下是一个错误:

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.
Run Code Online (Sandbox Code Playgroud)

唯一的区别是,类型oops推断Extendable代替的注释作为Extendablem是。并且您在调用oops.add(). 根据您的用例,这可能没什么大不了的,也可能是一个大问题。


好的,希望有帮助;祝你好运!

代码链接