【问题标题】:Typescript: Type T is not assignable to type 'never' when using Exclude打字稿:使用排除时,类型 T 不可分配给类型“从不”
【发布时间】:2021-12-05 08:53:56
【问题描述】:

我正在尝试:

  • 所有字段名称的列表
  • 无法排序的字段名称列表

我试图推断 ugh 是否是 unsortable 的补码。

function isUnsortableField<All extends string | number | symbol, T extends All, K extends Exclude<All, T>>(unsortable: Array<K>, field: All): field is T {
  return !!unsortable.find((f) => f === field)
}

const allFields = ['bar', 'zee'] as const;
const unsortableOnes: Array<typeof allFields[number]> = ['bar'];

const ugh = isUnsortableField(unsortableOnes, 'bar');

但是我得到:

Argument of type '("bar" | "zee")[]' is not assignable to parameter of type 'never[]'.
  Type 'string' is not assignable to type 'never'.
    Type 'string' is not assignable to type 'never'.ts(2345)

编辑:1000 只橡皮鸭之后,修复: 是:unsortable: Array&lt;K&gt;,但应该是 unsortable: Array&lt;T&gt;

function isSortableField<
  All extends PropertyKey,
  Unsorted extends All,
  K extends Exclude<All, Unsorted>
>(unsortable: Array<Unsorted>, field: All): field is K {
  return !unsortable.find((f) => f === field);
}

【问题讨论】:

  • unsortable 是什么意思?
  • 这只是一个用例。我有一个集合 A 和一个名为 B 的 A 子集(字段与不可排序的字段)。我想断言元素是否在 A 和 !B
  • 不是 100% 确定您要解决什么问题。如果您只是想以打字稿安全/运行时的方式确保数组中的某些内容,则执行 unsortableOnes.includes('bar') 可以。 IOW:如果你这样做了unsortableOnes.includes('xyz') typescript 会抱怨。
  • 在函数的第三个通用参数中,您将排除所有扩展所有的东西,这将始终解析为 never

标签: typescript types type-conversion typeerror


【解决方案1】:

在您的函数的第三个通用参数中,您正在从所有扩展所有的东西,并且由于 T 是所有的超集,它将排除所有内容并解析为 never

type A = {}


function test<T extends A, B extends Exclude<T, A>>(b: B) {

}

type Params = Parameters<typeof test>; // [b: never]

【讨论】:

  • 不确定我是否得到了“全部扩展”部分。我怎样才能通过以下内容:Playground
【解决方案2】:

你可以这样做:

const allFields = ['bar', 'zee'] as const;

function isUnsortableField<
    Prop extends PropertyKey,
    Unsortable extends Array<typeof allFields[number]> & Prop[],
    >(unsortable: [...Unsortable], field: any): field is Unsortable[number] {
    return unsortable.includes(field)
}

const unsortableOnes = ['bar'];

let field = 'baz'

if (isUnsortableField(['bar'], field)) {
    const x = field // "bar"
} else{
    const x = field // string
}

Playground

我使用了field: any,因为已知Array.prototype.includes issue

AFAIK,您可以在上述问题中找到几种解决方法,但所有这些方法都需要您重新声明 ReadonlyArray 的内置类型或使用类型断言。因此,您可以选择一个。

【讨论】:

  • 我想我解决不了任何问题。我仍然坚持使用 `x = field // 'bar' | '泽'。我想知道给定: - allFields: Array - 不可排序:Array then x = field // 'bar'
  • @PaulFelice 将unsortableOnes 替换为["bar"],您将获得bar 作为字段。如果要使用 Array&lt;typeof allFields[number]&gt; 类型约束,则需要将其添加到函数声明中,而不是显式键入 unsortableOnes
  • 我将if (isUnsortableField(['bar'], field)) 替换为isUnsortableField(unsortableOnes, field) 并得到Argument of type 'string[]' is not assignable to parameter of type '("bar" | "zee")[]'. Type 'string' is not assignable to type '"bar" | "zee"'
  • 这是因为unsortableOnes 被评估为字符串[]。您应该使用as const 或显式使用Array&lt;typeof allFields[number]&gt;。请记住,如果您对 unsortableOnes 使用显式类型 Array&lt;typeof allFields[number]&gt; ,则 field 变量将是 allFields 中所有元素的并集
猜你喜欢
  • 2021-07-23
  • 2021-10-11
  • 2020-06-29
  • 2021-11-10
  • 1970-01-01
  • 2019-09-25
  • 1970-01-01
  • 2022-08-14
  • 2016-10-25
相关资源
最近更新 更多