【问题标题】:How to properly "extend" a Record<>?如何正确“扩展” Record<>?
【发布时间】:2021-01-31 06:17:42
【问题描述】:

type SingleValue =  string | number | bigint | boolean | null 
type Value = SingleValue | SingleValue[]


function insert<T extends Record<string,Value>>(x: T) {

}

interface User {
  id: number
  name: string
}

insert<User>({  // <-- error
  id: 1,
  name: 'mpen',
})

https://go.mpen.ca/5reow

这给出了一个错误:

类型“用户”不满足约束“记录”。
“用户”类型中缺少索引签名。(2344)

我知道User 缺少像{[prop: string]: Value} 这样的索引签名,但我想要insert 只获取带有字符串键和Value 值的对象。 p>

我怎样才能以这种方式限制insert

【问题讨论】:

  • 不相关:可以将Value简化为type Value = string | number | bigint | boolean | null | Value[];
  • @AlekseyL。那实际上是等效的吗?不是递归的吗?即将允许[["foo"]]?
  • 是的,它是递归的,将允许[["foo"]]。这是从 Typescript 3.7 github.com/microsoft/TypeScript/pull/33050 开始允许的
  • @AlekseyL。是的..这是一个不错的功能,但不是我想要的:-)

标签: typescript


【解决方案1】:

你应该试试这个:

type SingleValue =  string | number | bigint | boolean | null 
type Value = SingleValue | SingleValue[]


function insert<T extends Record<keyof T,Value>>(x: T) {

}

interface User {
  id: number;
  name: string;
}

insert<User>({  // <-- no error anymore
  id: 1,
  name: 'mpen',
})

解释:

Record 类型需要不同的键类型,您可以将其指定为键的联合类型。但是,如果您指定像string 这样的数据类型,则输入类型必须具有索引签名。

【讨论】:

  • 但这不会限制输入类型只有stringtypescriptlang.org/play?#code/…
  • @AlekseyL。是的,但要添加该限制,您需要在输入类型中定义索引签名。在这种情况下,User 类型可以定义为interface User { [key:string]: number | string }。此外,typescript 允许在索引本身中使用非常有限的类型(基本上是 stringnumber)。默认情况下,JavaScript 对任何给定对象的所有索引都隐式调用 toString(除非我们正在处理数组)。在上面的示例中,我们使用 User 类型,它具有不同的键,这些键已经是字符串类型。因此,进行额外的索引类型检查是不合逻辑的。
  • @SachinSingh Ah.. 是的,不,它没有。这是有道理的,因为符号必须具有特定的值。
  • 我并不是说这是错误的,但要满足问题中的要求(对键和值的限制),您需要类似 typescriptlang.org/play?#code/…
  • @AlekseyL。您的第二个解决方案似乎很有趣。我删除了我之前的评论,因为我犯了一个错误,但它似乎有效!感谢您的讨论! :)
【解决方案2】:

解决方案是像这样更改insert 的签名:

function insert(x: Record<string,Value>) {
  return x
}

// This is allowed
insert({
  id: 1,
  name: 'mpen',
})

/**
 * This gives the error:
 *
 * Argument of type 'number[]' is not assignable to parameter of type 'Record<string, Value>'.
 * Index signature is missing in type 'number[]'.
 */
insert([1, 2, 3])

它将您的输入值限制为定义的记录类型,并且不允许其他值进入,在此示例中,使用键为数字类型的数组。

【讨论】:

  • 如果我从插入中删除 &lt;User&gt;,工具将无法帮助我发现错误。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-08-26
相关资源
最近更新 更多