2 ms·
My first thought was, this looks like a type system, except you need to solve it yourself. In Typesecript, naively: const main = <a extends any, b extends
by pcthrowaway 3y ago
My first thought was, this looks like a type system, except you need to solve it yourself. In Typesecript, naively:
const main = <a extends any, b extends any, c extends any>([a_, b_, c_]: [a, b, c, a]) => {
type SomeTuple = [a, b, c, a];
const X: a = a_;
const Y: Exclude<SomeTuple, a> // = <put solved value here, get a type error if the value does not satisfy the constraints>
console.log(X, Y);
}
Except nothing solves this because a, b, and c can all be the same. After trying to express this correctly, I ended up with something that appears useable (but that still uses assertions and doesn't really express the type of Y correctly).
type Narrowable = string | number | bigint | boolean;
/*
Express the type of a value in a tuple that is not the type of the second parameter
For example:
- ValOfTupleExceptFor<[1,1,6,2,3], 1> -> 6
- ValOfTupleExceptFor<[1,1,6,2,3], 6> -> 1
*/
type ValOfTupleExceptFor<
Tup extends readonly Narrowable[],
Val extends Tup[number]
> = Tup extends [infer First, ...(infer Rest extends Narrowable[])]
? First extends Val
? Rest extends []
? never
: ValOfTupleExceptFor<Rest, Val>
: First
: never;
const NO_SOLUTION: unique symbol = Symbol('NO_SOLUTION')
const getValOfTupleExcluding = (tup: readonly Narrowable[], val: (typeof tup)[number]): ValOfTupleExceptFor<typeof tup, typeof val> => {
const [first, ...rest] = tup;
if (!first) {
return NO_SOLUTION as never;
}
if (first === val) {
return getValOfTupleExcluding(rest, val);
}
return first as ValOfTupleExceptFor<typeof tup, typeof val>;
}
const main = <a extends Narrowable, b extends Narrowable, c extends Narrowable>([a_, b_, c_]: [a, b, c, a]) => {
const someTuple = [a_, b_, c_, a_] as const;
const X: a = a_;
// This still resolves to type 'never'
const Y: ValOfTupleExceptFor<typeof someTuple, a> = getValOfTupleExcluding(someTuple, a_);
console.log(X, Y);
}
Which really highlights how powerful the 'planner' style program is in terms of simplicity and conciseness. I guess Typescript isn't even powerful enough to express this kind of constraint.
edit: TS playground link with some experiments if anyone's interested: http://tinyurl.com/3p2pzdtn http://tinyurl.com/3p2pzdtn