Typescript - 逐步扩展对象的类型

Typescript - extending object's type progressively

我正在尝试使用 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 例如)

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

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

TypeScript 3.7 引入了 assertion functions which can be used to narrow the type of passed-in arguments or even this. Assertion functions look kind of like user-defined type guards,但您在类型谓词之前添加了一个 asserts 修饰符。以下是如何将 Extendable 实现为 class,并将 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; assertion functions only work if they have an explicitly annotated type. According to the relevant pull request、"this particular rule exists so that control flow analysis of potential assertion calls doesn't circularly trigger further analysis."

这意味着以下是错误的:

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.

唯一的区别是 oops 的类型被 推断 Extendable 而不是 注释的 正如 Extendablem 一样。调用 oops.add() 时出现错误。根据您的用例,这可能没什么大不了的,也可能是一个阻碍。


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

Link to code