【问题标题】:Mapped Type with Prefix for each Property每个属性的带有前缀的映射类型
【发布时间】:2021-08-23 18:20:50
【问题描述】:

我想创建一个只允许以给定前缀开头的属性的类型:

const example = {
  '#prop1': () => {},
  '#prop2': () => {}
} 

因此,在这种情况下,每个属性都必须以 # 为前缀。我在»Mapped Types« 中玩过»Template Literal Types«,就像这样:

interface WithD {
  [s: `#${string}`]: () => void
}

但这会产生这个错误:

索引签名参数类型必须是“字符串”或“数字”。

有什么办法可以做到吗?

【问题讨论】:

  • 映射类型假定您有一个类型并将其属性映射到其他东西。 Record 将与工会合作。但是在这两种情况下,您都需要有限数量的选项,我怀疑 TS 会在随机属性上做正则表达式。

标签: typescript template-literals conditional-types mapped-types


【解决方案1】:

就像@Nadia Chibrikova 所说,如果不预先知道example 的价值,就无法建立WithD

处理它的唯一方法是知道(能够推断)您要验证的类型。


type Validation<T extends Record<string, any>> = {
  [Prop in keyof T]: Prop extends `#${string}` ? T[Prop] : never
}

type Assert<T, U> = T extends U ? U extends T ? true : false : false


const example1 = {
  '#prop1': () => { },
  '#prop2': () => { },
}

const example2 = {
  ...example1,
  'prop3': () => { }
}

type Example1 = typeof example1;
type Example2 = typeof example2;


type Result1 = Assert<Example1, Validation<Example1>> // true
type Result2 = Assert<Example2, Validation<Example2>> // false


const isValid = <T extends Validation<T>>(arg: T) => { }
isValid(example1) // ok
isValid(example2) // expected error

Playground

因此,TS 应该从函数参数或类型泛型参数推断您的类型

【讨论】:

  • 谢谢!听到这是不可能的,有点难过,但也很高兴知道;)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-23
  • 2023-03-25
  • 2017-04-04
相关资源
最近更新 更多