首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >自动完成和参数推理不能同时在映射类型和类型副本泛型上工作

自动完成和参数推理不能同时在映射类型和类型副本泛型上工作
EN

Stack Overflow用户
提问于 2022-06-12 16:19:35
回答 2查看 123关注 0票数 0

在下面的代码(游乐场)中,我试图使autocompletion函数签名推理同时在personTypeX({...}) 中工作,但只能实现这两种功能之一,但不能同时实现两者。

有可能吗?

以下是要求:

  • 如果一个人(=输入)有一个firstName,那么它必须是一个string
  • 如果一个人有一个age,那么它必须是一个number
  • ..。
  • 如果一个人的属性不是firstNamelastNameagefavouriteFoodgetLegCount,那么该属性的值本身必须是Person

总共有3项额外所需资源

  • 必须检测到无效输入(在输入的任何级别)并在正确位置标记。参见:与personType1()personType2()一起工作
  • firstName中所有键的自动完成,.,getLegCount必须在personTypeX({})中提供--参见下面的内容:当前只在personType2({})中工作
  • 如果键(此处只有getLegCount)强制其值为函数,则必须正确推断函数签名如下:当前仅在personType1({})中工作。
代码语言:javascript
复制
type FixedType = {
  firstName: string,
  lastName: string,
  age: number,
  favouriteFood: string[],
  getLegCount: (numHeads: number) => number,
};

type PersonType<T> = {
  [K in (keyof T | keyof FixedType)]?:
    K extends keyof FixedType
      ? FixedType[K]
      : K extends keyof T
        ? T[K] extends object
          ? PersonType<T[K]>
          : PersonType<{}>
        : never
}

// ---- ---- ---- ---- ----

function personType1<T extends PersonType<T>>(t: T) { // signature version 1
  return t;
}

const person11 = personType1({
  firstName: 'Mark',
  lastName: 'Antony',
  holger: {
    age: 12,
    paul: {
      // <-- type 'a' for autocompletion of 'age' => NOT WORKING
      favouriteFood: ['cheese'],
      firstName: 'Paul',
      getLegCount: (numHeads) => 2, // <-- hover over 'numHeads' => numHeads: number correctly inferred => WORKING
    }
  },
});

// ----

function personType2<T extends PersonType<T>>(t: T & PersonType<T>) { // signature version 2
  return t;
}

const person1 = personType2({
  firstName: 'Mark',
  lastName: 'Antony',
  holger: {
    age: 12,
    paul: {
      // <-- type 'a' for autocompletion of 'age' => WORKING
      favouriteFood: ['cheese'],
      firstName: 'Paul',
      getLegCount: (numHeads) => 2, // <-- hover over 'numHeads' => numHeads: any inferred => NOT WORKING
                                    // that's probably bc it's the most common signature for
                                    //   (property) getLegCount: ((numHeads: any) => number) & ((numHeads: number) => number)
                                    // but I have no clue how to fix this
    }
  },
});
EN

回答 2

Stack Overflow用户

发布于 2022-06-14 23:17:38

简而言之,你现在所要求的是不可能的(就我的理解而言)。

这里有很多循环逻辑,它是TS的一个限制(在管理/理解这类代码方面是对人类的冒犯)。实际上,我们在泛型中使用泛型来规避它,但我们仍然受到它的限制。也就是说,根据我的理解,我们只能选择一个:

  • 检索参数的数据类型,验证参数的数据类型(IE ),并使其成为参数的数据类型。自动完成)
  • 验证参数是否合适,转换为自身的推断类型(getLegCount: (numHeads) => 2),使参数的数据类型(IE )。关于非显式类型的参数推断()

这方面的一个例子是,当我们回到泛型是如何制作的时候。

代码语言:javascript
复制
function example<T>(t: T)

在这里,我们可以显式定义T以规定t遵循,也可以从t推断T

当我们这样做的时候:

代码语言:javascript
复制
function personType<T extends PersonTypeNew<T>>(t: T){...}

我们正在制作循环逻辑,在某些时候TS必须选择Tt。(尽管他们彼此依赖,但他们创造了不同的结果)。

  • 如果我们推断参数(从而键入getLegCount: (numHeads),则推断age为空(因为它不在参数中),并且不需要为age (或任何其他键)提供自动完成功能。
  • 否则,默认行为提供自动完成。

从技术上讲,这是一个超级超级简化。这实际上在简单类型对象(即。(非循环的)带有称为部分推理的东西,这将允许自动完成和参数推断。

如果这让人困惑的话,在操场上有一些例子。

不管怎样,我把它从头开始重写了。支持自动完成和参数推断,但只有前者不存在。

代码语言:javascript
复制
type PersonTypeNew<T> = {
  // We have to overwrite any keys, otherwise we could incorrectly infer.
  // Hence Omit<T, keyof FixedType>, we use & Partial<FixedType> for correct autocompletion
  [K in keyof (Omit<T, keyof FixedType> & Partial<FixedType>)]: 
    K extends keyof FixedType
      ? FixedType[K]
      : (Omit<T, keyof FixedType> & Partial<FixedType>)[K] extends Record<string, any>
        ? PersonTypeNew<(Omit<T, keyof FixedType> & Partial<FixedType>)[K]>
        : "Invalid Value!"
}

这也增加了第一层的自动完成(当你没有推断)。

在没有自动完成支持的情况下,它要简洁得多(因为我们只是验证而不交叉两种对象类型)

代码语言:javascript
复制
type PersonTypeNewNoAutocomplete<T> = {
  [K in keyof T]?: 
    K extends keyof FixedType
      ? T[K] extends FixedType[K]
        ? T[K]
        : FixedType[K]
      : PersonTypeNewNoAutocomplete<T[K]>
}

查看游乐场以获取示例

还有一些尚未解决的问题正在讨论这一问题,本文将进一步详细介绍上下文引擎、优先级、循环类型的其他相关主题:

票数 1
EN

Stack Overflow用户

发布于 2022-06-20 16:53:39

检查一下,它的工作方式是使用Partial<FixedType>进行自动完成,使用K extends keyof FixedType ? FixedType[K]检查错误,并为嵌套对象使用递归的泛型类型。

游乐场

代码:

代码语言:javascript
复制
type TypeCheckedInferedPerson<T> = Partial<FixedType> & PersonType<T>

type PersonType<T extends Partial<FixedType>> = {
  [K in keyof T]: K extends keyof FixedType ? FixedType[K] : TypeCheckedInferedPerson<T[K]> 
}

function personType2<T extends PersonType<T>>(t: TypeCheckedInferedPerson<T>) { 
  return t;
}

结果:

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

https://stackoverflow.com/questions/72593943

复制
相关文章

相似问题

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