At all, my aim is to make a function that takes 2 string arrays as arguments and the second one should not include elements of the first:
function doSomething<
const T extends string,
const K extends StringExcept<T>
>(
firstArray: T[],
secondArray: K[]
) {}
doSomething(['a', 'b'], ['c', 'b']) // 'b' in the second array should cause type error
Firstly, I thought, that I need a type type like type StringExcept<T>
, which should work this way:
type NotAbc = StringExcept<'abc'>;
const notAbcArray:NotAbc[] = [
'any string', // okay
'123', // okay
'abc' // not allowed
]
What i have tried is using Exclude<>
type, like Exclude<string, 'abc'>
, but it does not work like this, and gives just string
type. Also I have tried different variations like T extends K ? never : T
statement, but then I found out that type Exclude does literally the same
Then I have found this question, which says that type like StringExcept
is impossible in TS for now (but if there are some updates, I would like to know). Also I have seen this experimental feature, that is closed now.
So, is there a way to make my doSomething(firstArray, secondArray)
function, using type like StringExcept
or not?
You could use the Exclude
utility type within the type of secondArray
itself:
function doSomething<
const T extends string,
const U extends string
>(
firstArray: T[],
secondArray: Exclude<U, T>[]
) { }
This will cause U
to be inferred as the elements of secondArray
, and then checked against Exclude<U, T>
:
doSomething(['a', 'b'], ['c', 'd']); // okay
doSomething(['a', 'b'], ['c', 'b']); // error!
// -------------------------> ~~~
// Type '"b"' is not assignable to type '"c"'.
This works because both T
and U
will (hopefully) be a union of string literal types, and Exclude
can filter such unions (whereas it cannot filter non-union types like string
itself).
It would be even nicer if we could put Exclude<U, T>
in the constaint for U
instead, like const U extends string & Exclude<U, T>
, but that is seen by the compiler as illegally circular. So we can move it down into the parameter type.