不确定标题是否明确(在一句中描述这个问题并不容易),但这里有一些代码来说明这个问题(在代码块之后有更多关于这个问题的详细信息):
type AttributeDefinition = {
name:string
type: 'string' | 'number',
}
type EntityDefinition = {
attributes: Readonly<AttributeDefinition[]>
}
export type Entity<ET extends EntityDefinition> = {
[K in ET['attributes'][number] as K['name']]:
K['type'] extends 'string' ? string :
K['type'] extends 'number' ? number :
never
}
const def1 = {
attributes: [
{name:'foo', type: 'string'},
{name:'baz', type: 'number'},
] as const
}
const def2: EntityDefinition = {
attributes: [
{name:'foo', type: 'string'},
{name:'baz', type: 'number'},
] as const
}
const entity1: Entity<typeof def1> = {
foo: 'bar',
baz: 42
}
const entity2: Entity<typeof def2> = {
foo: 'bar',
baz: 42
}因此,我的问题是,当我要将entity2分配给foo ( 42到baz)时,类型记录会在foo上抛出一个错误。问题是TS2322: Type 'string' is not assignable to type 'never'。
但是,entity1不会出现此问题。
这个问题的根源似乎与def2的声明有关,我对EntityDefinition类型进行了注释。我这样做是为了让我的IDE输入提示,帮助我正确声明def2对象。
但是,def1对象,即使没有带注释的类型,在创建entity1时也会被正确地处理,而def2 (我希望以正确的方式键入)在用于创建entity2时会失败。
我并不确定为什么它会以这种方式失败,以及如何像对def2那样注释对象,以及如何像对entity1那样使用这样的对象。
谢谢!
发布于 2022-03-24 20:29:17
Entity<typeof def2>失败的原因是注释扩大了def2的类型,这导致了细节的丢失。Entity<typeof def2>的类型等于Entity<EntityDefinition>,它的计算值为{[x: string]: never}。
您可能会创建一个保存信息的泛型类型注释,但随后必须在常量类型中指定泛型参数,这将导致重复的代码。
处理这一问题的方法是创建一个构造函数,它只返回参数,但对其有一个约束:
const mkEntityDefinition = <T extends EntityDefinition>(def: T) => def你可以这样使用它:
const def3 = mkEntityDefinition({
attributes: [
{name:'foo', type: 'string'},
{name:'baz', type: 'number'},
] as const
})
export const entity3: Entity<typeof def3> = {
foo: 'bar',
baz: 42
}它还能防止错误:
const defBad = mkEntityDefinition({
attributes: [
{name:'foo', type: 'strrring'},
{name:'baz', type: 'number'},
] as const
})
// Error: Type '"strrring"' is not assignable to type '"string" | "number"'.
// Did you mean '"string"'?发布于 2022-03-24 20:28:28
在satifies进入TS之前,您可以使用受约束的标识函数在编辑器中物理键入定义时提供IntelliSense帮助,同时仍然允许编译器推断其(更具体的)文字属性:
function createEntityDefinition <T extends EntityDefinition>(def: T): T {
return def;
}
const def2 = createEntityDefinition({
attributes: [
{name:'foo', type: 'string'},
{name:'baz', type: 'number'},
] as const,
});
const entity2: Entity<typeof def2> = {
foo: 'bar',
baz: 42,
}; // ok 发布于 2022-03-24 20:21:10
我相信有一个即将到来的特性来解决这个特定的用例:“满足”操作符,以确保表达式与某种类型(反馈重置) #47920匹配
const def2 = {
attributes: [
{name:'foo', type: 'string'},
{name:'baz', type: 'number'},
] as const
} satisfies EntityDefinition;它仍在开发中,但您可以在分期游乐场上查看一个工作示例。
https://stackoverflow.com/questions/71608464
复制相似问题