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
而不是 注释的 正如 Extendable
和 m
一样。调用 oops.add()
时出现错误。根据您的用例,这可能没什么大不了的,也可能是一个阻碍。
好的,希望对您有所帮助;祝你好运!
我正在尝试使用 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
而不是 注释的 正如 Extendable
和 m
一样。调用 oops.add()
时出现错误。根据您的用例,这可能没什么大不了的,也可能是一个阻碍。
好的,希望对您有所帮助;祝你好运!