Closed
Description
TypeScript Version: 3.9.1-rc
Search Terms:
Expected behavior:
Type should be narrowed to successfully call the action
method
Actual behavior:
Error
Related Issues:
Code
export type StepState<T = {}> = T & { counter: number; confirm?: boolean; startingStep?: number };
interface Repository {
path: string;
}
interface State {
repos: string | string[] | Repository | Repository[];
createBranch?: string;
}
function steps(state: StepState<State>) {
if (state.repos != null && !Array.isArray(state.repos)) {
// Doesn't work without the cast, or the checks below
state.repos = [state.repos] as string[] | Repository[];
// if (typeof state.repos === 'string') {
// state.repos = [state.repos];
// } else {
// state.repos = [state.repos];
// }
}
// With the cast above, this will be:
// (property) State.repos: string[] | Repository[]
state.repos;
// But it can't be passed here, because it seems the type gets unnarrowed
// Argument of type 'StepState<State>' is not assignable to parameter of type '{ counter: number; confirm?: boolean | undefined; startingStep?: number | undefined; } & { repos?: string[] | Repository[] | undefined; }'.
// Type 'StepState<State>' is not assignable to type '{ repos?: string[] | Repository[] | undefined; }'.
// Types of property 'repos' are incompatible.
// Type 'string | Repository | string[] | Repository[]' is not assignable to type 'string[] | Repository[] | undefined'.
// Type 'string' is not assignable to type 'string[] | Repository[] | undefined'.(2345)
action(state);
}
function action<State extends StepState & { repos?: string[] | Repository[] }>(state: State) {
}
Output
function steps(state) {
if (state.repos != null && !Array.isArray(state.repos)) {
// Doesn't work without the cast, or the checks below
state.repos = [state.repos];
// if (typeof state.repos === 'string') {
// state.repos = [state.repos];
// } else {
// state.repos = [state.repos];
// }
}
// With the cast above, this will be:
// (property) State.repos: string[] | Repository[]
state.repos;
// But it can't be passed here, because it seems the type gets unnarrowed
// Argument of type 'StepState<State>' is not assignable to parameter of type '{ counter: number; confirm?: boolean | undefined; startingStep?: number | undefined; } & { repos?: string[] | Repository[] | undefined; }'.
// Type 'StepState<State>' is not assignable to type '{ repos?: string[] | Repository[] | undefined; }'.
// Types of property 'repos' are incompatible.
// Type 'string | Repository | string[] | Repository[]' is not assignable to type 'string[] | Repository[] | undefined'.
// Type 'string' is not assignable to type 'string[] | Repository[] | undefined'.(2345)
action(state);
}
function action(state) {
}
Compiler Options
{
"compilerOptions": {
"noImplicitAny": true,
"strictNullChecks": true,
"strictFunctionTypes": true,
"strictPropertyInitialization": true,
"strictBindCallApply": true,
"noImplicitThis": true,
"noImplicitReturns": true,
"alwaysStrict": true,
"esModuleInterop": true,
"declaration": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"moduleResolution": 2,
"target": "ES2017",
"jsx": "React",
"module": "ESNext"
}
}
Playground Link: Provided