Closed
Description
TypeScript Version: 3.9.2
Search Terms:
const assertion, literal narrowing
Code
const a1 = 'A1'
const a2 = 'A2'
const actionCreators = {
a1: () => ({type: a1}),
a2: (b: number) => ({type: a2, b}),
}
type Action = ReturnType<typeof actionCreators[keyof typeof actionCreators]>
export default (state = {}, action: Action) => {
switch (action.type) {
case a2:
return {...state, b: action.b}
default:
return state
}
}
Expected behavior:
Code with literal narrowing should compile, similar to the following code with an explicit const assertion:
const a1 = 'A1' as const
const a2 = 'A2' as const
...
Actual behavior:
Code does not compile.
Property 'b' does not exist on type '{ type: string; } | { type: string; b: number; }'.
Property 'b' does not exist on type '{ type: string; }'.(2339)
Related Issues:
Might be related to #9998.
Output
const a1 = 'A1'; // as const
const a2 = 'A2'; // as const
const actionCreators = {
a1: () => ({ type: a1 }),
a2: (b) => ({ type: a2, b }),
};
export default (state = {}, action) => {
switch (action.type) {
case a2:
return Object.assign(Object.assign({}, state), { b: action.b });
default:
return 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