Home > Blockchain >  Typescript: Type T is not assignable to type 'never' when using Exclude
Typescript: Type T is not assignable to type 'never' when using Exclude

Time:10-19

I am trying have a:

  • list of all field names
  • list of unsortable field names

I am trying to infer whether ugh is the complement of 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');

However I get:

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)

EDIT: 1000 rubber ducks later, fix: was: unsortable: Array<K> but should've been unsortable: Array<T>

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);
}

CodePudding user response:

In the 3rd generic parameter of your function you are Extending from All something that extends All, and since the T is a superset of All, it will exclude everything and resolve to never.

type A = {}


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

}

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

CodePudding user response:

You can do something like this:

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

I have used field: any because of known Array.prototype.includes issue

AFAIK, there are several workarounds you can find in above issue, but all of them requires you to either redeclare built in type of ReadonlyArray or use type assertions. Hence, it is up to you to choose one.

CodePudding user response:

the function you write has this signature in your call:

function isUnsortableField<"bar", "bar", never>(unsortable: never[], field: "bar"): field is "bar"

While the variable unsortableOnes that passed as the argument has a different type

const unsortableOnes: ("bar" | "zee")[]

IF you write this, the error were gone that shows that you must change the function signature

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

try this https://www.typescriptlang.org/play?ssl=10&ssc=17&pln=1&pc=1#code/GYVwdgxgLglg9mABDAzgVTCuAnKBDAIwBsBTAMRhKIBMAeAQSKMRIA8oSxqVEUpsYYAOaIAPojAgAtgRLYxvAJ4y4RADSIAKi3aduiRusQBpHRy49NAPgAU4LLkKkAXAezY8i2sasbglGldDAEpXfypqZEtEAG8AKEREbBIoEGwkAEIM xx8YhIAOn8uGxtgYMQAXitEYCrKytqA6mC4gF84uIgEPkQ8JgoInkaAbQByAjxsMY0xgC8SEjGAXT6ebswoAG44gHpdjd6cx3yAeTASFCD3T1ooRQAHEjg6-qJBmhQRyRk5ZZrRhMpisdl0elBECAhAALKpRDAOPKkD7UGwjABEk2w6OWsyxY2CoMOqkKRDgQjsMOCQA

  • Related