-
Notifications
You must be signed in to change notification settings - Fork 13k
Closed
Labels
DuplicateAn existing issue was already createdAn existing issue was already createdFix AvailableA PR has been opened for this issueA PR has been opened for this issue
Description
TypeScript Version:
3.3.1
Search Terms:
conditional types default
Code
// A *self-contained* demonstration of the problem follows...
// Test this by running `tsc` on the command-line, rather than through another build tool such as Gulp, Webpack, etc.
I want to give the user the ability to supply their own interface or default to a different structure:
export interface Config {
[key: string]:
| number[]
| string[]
| number
| string
}
export type AddArrayLike<T> = unknown extends T ? Config | Config[] : {
[P in keyof T]: T[P] | T[P][]
}
export interface INodeGroupProps<T = unknown, State = unknown> {
data: T[];
keyAccessor: (data: T, index: number) => string | number;
start: (data: T, index: number) => unknown extends State ? Config : State;
enter?: (data: T, index: number) => AddArrayLike<State>;
update?: (data: T, index: number) => AddArrayLike<State>;
leave?: (data: T, index: number) => AddArrayLike<State>;
}
So I have a State type argument that defaults to unknown. If it is unknown then it should be Config.
Everything works fine in this example of supplying your own State.
export type Point = {x: number, y: number};
export interface NodesState {
top: number;
left: number;
opacity: number;
}
const points: Point[] = [
{x: 0, y: 0},
{x: 1, y: 2},
{x: 2, y: 3}
]
const Test: INodeGroupProps<Point, NodesState> = {
data: points,
keyAccessor: (d) => {
return d.x
},
start: (point) => {
return {
top: point.y,
left: point.x,
opacity: 0
};
},
enter: (point) => {
return {
top: [point.y],
left: [point.x],
opacity: [0]
};
},
update: (point) => {
return {
top: [point.y],
left: [point.x],
opacity: 0
};
},
leave: (point) => {
return {
top: [point.y],
left: [point.x],
opacity: 0
};
},
};
I get type safety if I change one of the types from the NodeState interface to be not a number, e.g.
return {
top,
left,
opacity: true
};
But if I add a prop that is not part of the NodeState interface then this is not recognised as a break.
e.g.
return {
top,
left,
opacity: 0,
fook: 'blah' // not part of NodeState
};
Expected behavior:
fook
should be identified as not part of the NodeState
interface
Actual behavior:
No type error
Playground Link:
Related Issues:
Metadata
Metadata
Assignees
Labels
DuplicateAn existing issue was already createdAn existing issue was already createdFix AvailableA PR has been opened for this issueA PR has been opened for this issue