Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Generic return type only partially respected #40307

Closed
ivoiv opened this issue Aug 28, 2020 · 3 comments
Closed

Generic return type only partially respected #40307

ivoiv opened this issue Aug 28, 2020 · 3 comments
Labels
Duplicate An existing issue was already created Fix Available A PR has been opened for this issue

Comments

@ivoiv
Copy link

ivoiv commented Aug 28, 2020

TypeScript Version: 4.0.2 / 4.1.0-dev.20200828

Search Terms: generic return type not respected

This is a rather nonsensical reducer factory, taking a State and a Function as parameters.
The Function takes an argument which is the same type as the State and returns an object where keys can be any record type, and their values are basically copies of State.

I feel like I might be doing something wrong but I can't find any answer either in the FAQ or on StackOverflow.

Code

This does NOT throw an error, but it should:

function reducerFactory<
  T,
  K extends Record<any, T>
>(state: T, reducer: (state: T) => K) {}

reducerFactory({ a: 1 }, (state) => ({
  one: { ...state, b: 2 } // should throw error, but works fine
}));

This correctly throws an error

function reducerFactory<
  T,
  K extends Record<any, T>
>(state: T, reducer: (state: T) => K) {}

reducerFactory({ a: 1 }, (state) => ({
  one: { b: 2 } // Type '{ b: number; }' is not assignable to type '{ a: number; }'.
}));

This correctly throws an error

function reducerFactory<
  T,
  K extends Record<any, T>
>(state: T, reducer: (state: T) => K) {}

reducerFactory({ a: 1 }, (state) => ({
  one: { a: 'foo', b: 2 } // Type 'string' is not assignable to type 'number'.
}));

EDIT: I thought K extends Record was maybe somehow too vague so I made the return type a bit more explicit but still the same issue.

function reducerFactory<T>(
  state: T,
  reducer: (state: T) => { [key: string]: T }
) {}

reducerFactory({ a: 1 }, (state) => ({
  one: { ...state, b: 2 }, // should throw error but works fine
}));

Expected behavior:
Type '{ a: number, b: number; }' is not assignable to type '{ a: number; }'.
Object literal may only specify known properties, and 'b' does not exist in type '{ a: number; }'.

Actual behavior:
Code compiles without errors.

Playground Link:
https://www.typescriptlang.org/play?ts=4.1.0-dev.20200828#code/GYVwdgxgLglg9mABAZygQygUwMICdMZy4A8AKgDSIDSimAHlmACbKIBKmERTxaYAnpVIA+YQApUGTAC5EFRPiYgImXLInoss0gEpEAXmHU9Ab0QBfAFCXJWPAShExZtLICMFyrcwGjzxAgyiGYAdGHelABGsgBMFhY6OkA

Related Issues:

@RyanCavanaugh
Copy link
Member

Duplicate #241

This isn't per se unsafe, it's just an undetected excess property

@RyanCavanaugh RyanCavanaugh added the Duplicate An existing issue was already created label Aug 28, 2020
@ivoiv
Copy link
Author

ivoiv commented Aug 28, 2020

At first I was happy it was a duplicate issue, reassuring me I'm not just stupid and that it's a real problem.
Then my joy went away when I saw the original issue is 6 years old.

@RyanCavanaugh
Thanks for making TypeScript the amazing tool it is! ❤️
Good luck with the issue! 🤞

@typescript-bot
Copy link
Collaborator

This issue has been marked as a 'Duplicate' and has seen no recent activity. It has been automatically closed for house-keeping purposes.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Duplicate An existing issue was already created Fix Available A PR has been opened for this issue
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants