I have a component that accepts an array of keys
, and then passes one of those keys
to the children
render prop.
type PagerKeys = Readonly<[string, string, ...string[]]>; // needs to be at least 2 items
interface PagerProps<Keys extends PagerKeys> {
children: (
props: {
currentKey: Keys[number]
}
) => ReactNode;
keys: Keys;
}
function Pager<Keys extends PagerKeys>({
children, keys
}: PagerProps<Keys>) {
const [currentKey, setCurrentKey] = useState<Keys[number]>(keys[0]);
return children({
currentKey
});
}
I’m able to type check if the currentKey
in the render prop matches keys
by adding as const
to the keys
prop. (PagerKeys
above is Readonly
for that reason).
<Pager keys={['a', 'b'] as const}>
{({currentKey}) => {
if (currentKey === 'a') {}
if (currentKey === 'lalala') {} // throws error as it should because 'lalala' is not a key
...
}}
</Pager>
I’m wondering if there’s a way to infer the string literal in keys
without adding as const
?
2
Answers
TypeScript 5.0 introduced
const
type parameters that let you add aconst
modifier to type parameters to ask the compiler for the same sort of inference you’d get if someone used aconst
assertion. This makes it easy for generic function implementers to ask foras const
-like behavior without having to use more obscure tricks (such as those described in microsoft/TypeScript#30680).In your case the change is as simple as
And now when you call
The compiler infers the type parameter as
readonly ["a", "b"]
as desired:Playground link to code
Pre-5.0, this was still possible using variadic tuple types to infer the strings as literal types:
This is the only change necessary!
Playground