Closed
Description
TypeScript Version:
3.8.3
Search Terms:
I haven't really searched because I don't know what words to use for this. 😕
Expected behavior:
No Typescript errors or warnings when calling makeTable
.
Actual behavior:
Following Typescript errors and warnings:
rows
gets typestring[]
, rather thanData[]
, for some reasonrow
in the render function ends up as implicitlyany
regardless.
Typescript gets everything right if I rename one of the render
properties to something else, but shouldn't a discriminated union(?) work regardless of what name I use?
Plan was to use a if( 'field' in column )
type-guard, which would then tell me which parameters to call render
with, but Typescript started complaining before I even got there. 😕
Code
type Data = { id: number, name: string };
const data: Data[] = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
]
type Header = { header: string };
type ValueFromField<Row> = {
[Key in keyof Row]: {
field: Key;
render?: (value: Row[Key]) => string;
};
}[keyof Row];
type ValueFromRow<Row> = {
render: (row: Row) => string;
};
type Column<Row> = Header & (ValueFromField<Row> | ValueFromRow<Row>);
const makeTable = <Row>(rows: Row[], columns: Column<Row>[]) => {
// Pretend we're rendering a table here...
}
makeTable(data, [
{ header: 'Id', field: 'id' },
{ header: 'Name', field: 'name', render: value => value.toUpperCase() },
{ header: 'Both', render: row => `${row.id} : ${row.name}` },
])
makeTable(data, [
{ header: 'Id', field: 'id' },
{ header: 'Name', field: 'name', render: value => value.toUpperCase() },
])
makeTable(data, [
{ header: 'Test', render: row => `${row.id} : ${row.name}` },
])
Output
"use strict";
const data = [
{ id: 1, name: 'Alice' },
{ id: 2, name: 'Bob' }
];
const makeTable = (rows, columns) => {
// Pretend we're rendering a table here...
};
makeTable(data, [
{ header: 'Id', field: 'id' },
{ header: 'Name', field: 'name', render: value => value.toUpperCase() },
{ header: 'Both', render: row => `${row.id} : ${row.name}` },
]);
makeTable(data, [
{ header: 'Id', field: 'id' },
{ header: 'Name', field: 'name', render: value => value.toUpperCase() },
]);
makeTable(data, [
{ header: 'Test', render: row => `${row.id} : ${row.name}` },
]);
Compiler Options
{
"compilerOptions": {
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": true,
"strictBindCallApply": true,
"noImplicitThis": true,
"noImplicitReturns": true,
"useDefineForClassFields": false,
"alwaysStrict": true,
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"downlevelIteration": false,
"noEmitHelpers": false,
"noLib": false,
"noStrictGenericChecks": false,
"noUnusedLocals": false,
"noUnusedParameters": false,
"esModuleInterop": true,
"preserveConstEnums": false,
"removeComments": false,
"skipLibCheck": false,
"checkJs": false,
"allowJs": false,
"declaration": true,
"experimentalDecorators": false,
"emitDecoratorMetadata": false,
"target": "ES2017",
"module": "ESNext"
}
}
Playground Link: Provided