Issue
I am trying to do the following
function createRecord<T extends string>(key: T) : Record<T, T> {
return {[key]: key}; // Type '{ [x: string]: T; }' is not assignable to type 'Record<T, T>'
}
However is seems that the computed property is inferred as a string type by the typescript compiler rather than the string literal T, is it possible to implement the above function without any type assertions?
Solution
There's a longstanding open issue at microsoft/TypeScript#13948 noting that computed property keys are often widened to string
, and that this is often not what people want. Things work fine when your computed key is of a single string literal type:
const a = "a";
const x = { [a]: "" } // {a: string}, okay
But as soon as you have a union key
const ab = Math.random() < 0.5 ? "a" : "b" // const ab: "a" | "b"
const y = { [ab]: "" } // { [x: string]: string}, 😢
or a generic key
// (parameter) k: K extends PropertyKey
const z = { [k]: "" } // { [x: string]: string}, 😢
the type gets widened to a string index signature.
That issue is still open, with no obvious resolution in sight. Similar issues have been closed as design limitations; see microsoft/TypeScript#47703 for a fairly recent one.
That means, for now, if you want to see the compiler treat objects with computed keys as a different type, you'll have to use something like a type assertion to persuade it to do so. My suggestion for your createRecord()
would be
function createRecord<K extends string>(key: K) {
return { [key]: key } as { [P in K]: Record<P, P> }[K]
}
This behaves similarly to Record<K, K>
:
const aRec = createRecord("a"); // Record<"a", "a">
but you can see a difference when the type of key
is a union:
const abRec = createRecord(Math.random() < 0.5 ? "a" : "b")
// const abRec: Record<"a", "a"> | Record<"b", "b">
If you pass in either "a"
or "b"
, you want abRec
to be either {a: "a"}
or {b: "b"}
. If you left it as Record<K, K>
where K
is "a" | "b"
, then you'd get the type {a: "a" | "b"; b: "a" | "b"}
, which is not appropriate as it claims both keys are present.
Answered By - jcalz
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.