首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >类型注解时类型记录映射类型错误

类型注解时类型记录映射类型错误
EN

Stack Overflow用户
提问于 2022-03-24 19:37:22
回答 3查看 178关注 0票数 1

不确定标题是否明确(在一句中描述这个问题并不容易),但这里有一些代码来说明这个问题(在代码块之后有更多关于这个问题的详细信息):

代码语言:javascript
复制
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 ( 42baz)时,类型记录会在foo上抛出一个错误。问题是TS2322: Type 'string' is not assignable to type 'never'

但是,entity1不会出现此问题。

这个问题的根源似乎与def2的声明有关,我对EntityDefinition类型进行了注释。我这样做是为了让我的IDE输入提示,帮助我正确声明def2对象。

但是,def1对象,即使没有带注释的类型,在创建entity1时也会被正确地处理,而def2 (我希望以正确的方式键入)在用于创建entity2时会失败。

我并不确定为什么它会以这种方式失败,以及如何像对def2那样注释对象,以及如何像对entity1那样使用这样的对象。

谢谢!

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2022-03-24 20:29:17

Entity<typeof def2>失败的原因是注释扩大了def2的类型,这导致了细节的丢失。Entity<typeof def2>的类型等于Entity<EntityDefinition>,它的计算值为{[x: string]: never}

您可能会创建一个保存信息的泛型类型注释,但随后必须在常量类型中指定泛型参数,这将导致重复的代码。

处理这一问题的方法是创建一个构造函数,它只返回参数,但对其有一个约束:

代码语言:javascript
复制
const mkEntityDefinition = <T extends EntityDefinition>(def: T) => def

你可以这样使用它:

代码语言:javascript
复制
const def3 = mkEntityDefinition({
    attributes: [
        {name:'foo', type: 'string'},
        {name:'baz', type: 'number'},
    ] as const
})

export const entity3: Entity<typeof def3> = {
    foo: 'bar',
    baz: 42
}

它还能防止错误:

代码语言:javascript
复制
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"'?

TypeScript游乐场

票数 2
EN

Stack Overflow用户

发布于 2022-03-24 20:28:28

satifies进入TS之前,您可以使用受约束的标识函数在编辑器中物理键入定义时提供IntelliSense帮助,同时仍然允许编译器推断其(更具体的)文字属性:

TS游乐场

代码语言:javascript
复制
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 
票数 2
EN

Stack Overflow用户

发布于 2022-03-24 20:21:10

我相信有一个即将到来的特性来解决这个特定的用例:“满足”操作符,以确保表达式与某种类型(反馈重置) #47920匹配

代码语言:javascript
复制
const def2 = {
    attributes: [
        {name:'foo', type: 'string'},
        {name:'baz', type: 'number'},
    ] as const
} satisfies EntityDefinition;

它仍在开发中,但您可以在分期游乐场上查看一个工作示例。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/71608464

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档