当运行。compiler(tsc
)以transpile稿的代码成为可运行的JavaScript,语言是静态型的系统 抹去. 所以你的 Foo
类型(改名为大写字母,以满足TS命名约定)不存在任何形式在运行时间。 没有什么是你可以迭代要拿到钥匙 go
和 start
.
最直接的办法得到一些事情发生在运行时编写的JavaScript必要做到这一点,然后确定稿编译器可以给你坚强的类型你需要的话,你写的。 这基本上是 反向 的什么你想做的。
在你的情况:什么 generate()
需要为工作在运行时? 好吧,如果我们可以假定值产生的 generate()
会对象仅保持 string
-尊贵的特性,那么我们就需要通过它的一个列表中的按键对象。 那么,如果我们写的 generate()
做到这一点,然后定义 Foo
在输出 generate()
而不是周围的其他方式?
例如:
function generate<K extends PropertyKey>(...keys: K[]) {
return Object.fromEntries(keys.map(k => [k, ""])) as { [P in K]: string };
}
const myFooObject = generate("go", "start");
type Foo = typeof myFooObject;
/* type Foo = {
go: string;
start: string;
} */
console.log(myFooObject)
/* {
"go": "",
"start": ""
} */
在这里, generate()
是一个 通用的 职能,需要一个列表中的钥匙(类型 K
)和生产值的一种类型的钥匙在 K
和价值观的类型 string
. 那 {[P in K]: string}
是 映射类型 相当于 Record<K, string>
使用 的 Record<K, V>
实用新型.
执行使用 Object.fromEntries()
建立的对象、以及返回的类型是 声称 是正确的类型,因为稿看到 Object.fromEntries()
为返回的一个类型是太宽了我们的目的。
无论如何,当你打电话 const myFooObject = generate("go", "start")
它产生一个值的类型 {go: string; start: string}
,这是一样的 Foo
类型。 所以我们就可以定义 Foo
作为 type Foo = typeof myFooObject
而不是做手工。 你 可能 还在做手动,但有一点我要表示的是,它更加容易写 干代码 在。如果你开始的价值和类型产生自他们,而不是试图这样做的其他方式。
再次,如果使用该稿的编译器 tsc
因为-是的,那种类型删除阻止你写作 generate()
从定义 Foo
. 但是...
如果你愿意增加一个建设步骤,项目和执行 代码生成 利用该 稿的编译器API 或类似的东西,然后你可以做任意的事情与类型。 那里是图书馆做类似的事情你想要什么;例如, ts-自动模拟 权利要求产生模拟对象给予对象类型,它看起来像完全是您的使用情况。
这样的一个额外的建造步骤可能是一个合理的办法,但如果走这条路,你应该注意,你不用只是简单的稿了(并因此专题的可能范围之内的问题只是一稿标签)。
游乐场链接,以代码