I have the following type definitions.
type Key<Row> = {
[P in keyof Row]: Row[P] extends string ? P : never
}[keyof Row];
type ID<Row> = Row[Key<Row>];
type Selected<Row> = {
selected: boolean;
} & Row;
Key<Row>
returns all the property keys of Row
whose values are strings. See this answer for how it is constructed.
ID<Row>
is a union of all the string values of Row
. It is always a string
but narrows nicely if the string value is a string constant, e.g. in
interface X {
prop: "abc";
}
ID<X>
is always "abc"
.
Selected<Row>
is an intersection type of whatever Row
is plus the property selected: boolean
.
With all the above defined, I don't understand why the below function definition throws an error:
const getId = <Row>(row: Selected<Row>, key: Key<Row>): ID<Selected<Row>> =>
row[key];
The type error TS gives me is pasted below, but I can't work out why TS doesn't like my code.
From what I can see row[key]
should always work because even if row
is Selected<Row>
, Key<Row>
only contains a narrower set of keys, so what's the problem with keying into an object that has more properties than the key we're actually using?
Here is a link to the TS playground with this code showing the error
Type 'Selected<Row>[{ [P in keyof Row]: Row[P] extends string ? P : never; }[keyof Row]]' is not assignable to type '{ selected: boolean; }[(Selected<Row>[keyof Row] extends string ? keyof Row : never) & (Selected<Row>["selected"] extends string ? "selected" : never)] & Row[(Selected<Row>[keyof Row] extends string ? keyof Row : never) & (Selected<...>["selected"] extends string ? "selected" : never)]'.
Type 'Selected<Row>[Row[keyof Row] extends string ? keyof Row : never]' is not assignable to type '{ selected: boolean; }[(Selected<Row>[keyof Row] extends string ? keyof Row : never) & (Selected<Row>["selected"] extends string ? "selected" : never)] & Row[(Selected<Row>[keyof Row] extends string ? keyof Row : never) & (Selected<...>["selected"] extends string ? "selected" : never)]'.
Type 'Selected<Row>[keyof Row]' is not assignable to type '{ selected: boolean; }[(Selected<Row>[keyof Row] extends string ? keyof Row : never) & (Selected<Row>["selected"] extends string ? "selected" : never)] & Row[(Selected<Row>[keyof Row] extends string ? keyof Row : never) & (Selected<...>["selected"] extends string ? "selected" : never)]'.
Type 'Row[string] | Row[number] | Row[symbol]' is not assignable to type '{ selected: boolean; }[(Selected<Row>[keyof Row] extends string ? keyof Row : never) & (Selected<Row>["selected"] extends string ? "selected" : never)] & Row[(Selected<Row>[keyof Row] extends string ? keyof Row : never) & (Selected<...>["selected"] extends string ? "selected" : never)]'.
Type 'Row[string]' is not assignable to type '{ selected: boolean; }[(Selected<Row>[keyof Row] extends string ? keyof Row : never) & (Selected<Row>["selected"] extends string ? "selected" : never)] & Row[(Selected<Row>[keyof Row] extends string ? keyof Row : never) & (Selected<...>["selected"] extends string ? "selected" : never)]'.
Type 'Row[string]' is not assignable to type '{ selected: boolean; }[(Selected<Row>[keyof Row] extends string ? keyof Row : never) & (Selected<Row>["selected"] extends string ? "selected" : never)]'.
Type 'Row' is not assignable to type '{ selected: boolean; }'.
Type 'Row[string]' is not assignable to type 'boolean'.
Type 'Selected<Row>[keyof Row]' is not assignable to type '{ selected: boolean; }[(Selected<Row>[keyof Row] extends string ? keyof Row : never) & (Selected<Row>["selected"] extends string ? "selected" : never)]'.
Type 'keyof Row' is not assignable to type '(Selected<Row>[keyof Row] extends string ? keyof Row : never) & (Selected<Row>["selected"] extends string ? "selected" : never)'.
Type 'keyof Row' is not assignable to type 'Selected<Row>[keyof Row] extends string ? keyof Row : never'.
Type 'Selected<Row>[keyof Row]' is not assignable to type 'boolean'.
Type 'Selected<Row>[Row[keyof Row] extends string ? keyof Row : never]' is not assignable to type '{ selected: boolean; }[(Selected<Row>[keyof Row] extends string ? keyof Row : never) & (Selected<Row>["selected"] extends string ? "selected" : never)]'.
Type 'Row[keyof Row] extends string ? keyof Row : never' is not assignable to type '(Selected<Row>[keyof Row] extends string ? keyof Row : never) & (Selected<Row>["selected"] extends string ? "selected" : never)'.
Type 'Row[keyof Row] extends string ? keyof Row : never' is not assignable to type 'Selected<Row>["selected"] extends string ? "selected" : never'.
Type 'Selected<Row>[Row[keyof Row] extends string ? keyof Row : never]' is not assignable to type 'boolean'.
Type 'Selected<Row>[{ [P in keyof Row]: Row[P] extends string ? P : never; }[keyof Row]]' is not assignable to type '{ selected: boolean; }[(Selected<Row>[keyof Row] extends string ? keyof Row : never) & (Selected<Row>["selected"] extends string ? "selected" : never)]'.
Type 'Row[keyof Row] extends string ? keyof Row : never' is not assignable to type '(Selected<Row>[keyof Row] extends string ? keyof Row : never) & (Selected<Row>["selected"] extends string ? "selected" : never)'.
Type 'keyof Row' is not assignable to type '(Selected<Row>[keyof Row] extends string ? keyof Row : never) & (Selected<Row>["selected"] extends string ? "selected" : never)'.
Type 'string | number | symbol' is not assignable to type '(Selected<Row>[keyof Row] extends string ? keyof Row : never) & (Selected<Row>["selected"] extends string ? "selected" : never)'.
Type 'string' is not assignable to type '(Selected<Row>[keyof Row] extends string ? keyof Row : never) & (Selected<Row>["selected"] extends string ? "selected" : never)'.
Type 'string' is not assignable to type 'Selected<Row>[keyof Row] extends string ? keyof Row : never'.
Type 'keyof Row' is not assignable to type 'Selected<Row>[keyof Row] extends string ? keyof Row : never'.
Type 'string | number | symbol' is not assignable to type 'Selected<Row>[keyof Row] extends string ? keyof Row : never'.
Type 'string' is not assignable to type 'Selected<Row>[keyof Row] extends string ? keyof Row : never'.
Type 'Row[keyof Row] extends string ? keyof Row : never' is not assignable to type 'Selected<Row>["selected"] extends string ? "selected" : never'.
Type 'Selected<Row>[{ [P in keyof Row]: Row[P] extends string ? P : never; }[keyof Row]]' is not assignable to type 'boolean'.
Type 'Selected<Row>[Row[keyof Row] extends string ? keyof Row : never]' is not assignable to type 'boolean'.
Type 'Selected<Row>[keyof Row]' is not assignable to type 'boolean'.
Type 'Row[string] | Row[number] | Row[symbol]' is not assignable to type 'boolean'.
Type 'Row[string]' is not assignable to type 'boolean'.