-
Notifications
You must be signed in to change notification settings - Fork 12.8k
Type inference in generic return type #18839
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
Comments
It looks like you're right; we do allow this for any individual type extending
|
Consider: interface LiteralBase extends Base { id: "literal" }
const spec: Spec<LiteralBase> = makeSpec("whoops"); // no error!! Your You could presumably do this: export const makeSpec = <T extends Base>(id: T['id']): Spec<T> => {
return { id } // still error
}
const spec: Spec<LiteralBase> = makeSpec("whoops"); // error, "whoops" is not compatible which at least avoids the unsafeness of calling export const makeSpec = <T extends Base>(id: T['id']): Spec<T> => {
return { id } as Partial<T> // or Spec<T>
} Not sure if the need for the assertion is a bug, design limitation, or some actual safety measure I'm overlooking. |
In your situation, you could also just describe exactly what the function does without involving interface Base { id: string }
interface Sub extends Base { id: "sub", other: number }
export const makeSpec = <T extends string>(id: T): { id: T } => {
return { id }
}
const s: Partial<Sub> = makeSpec("sub"); |
Thanks, @jcalz for providing one possible edge case of string literals. I have been using the workaround to force the type but couldn't understand typescript's behaviour. I use a complex, long chain of interfaces so not involving |
I found one more error case which may be manifested because of the same issue in typescript. type Diff<T extends string, U extends string> = ({[P in T]: P } & {[P in U]: never } & { [x: string]: never })[T]
type Omit<T, K extends keyof T> = {[P in Diff<keyof T, K>]: T[P]}
interface Base { id: string, val: number }
const makeSpec = <T extends Base>(valObj: Omit<T, "id">) => {
const value = valObj.val
const valObj2: Omit<T, "id"> = { val: 456 }
} It errors on third last line with the error But this one complies fine interface A extends Base { }
const valObj: Omit<A, "id"> = { val: 123 } Can someone from TS team weigh in on how to resolve this one? Even being able to compile without removing |
Automatically closing this issue for housekeeping purposes. The issue labels indicate that it is unactionable at the moment or has already been addressed. |
TypeScript Version: 2.5.3
(Tested at https://www.typescriptlang.org/play/)
Looks like Typescript is not correctly evaluating the generic return type where all the fields are optional.
Here is the minimal case.
Code
Expected behavior:
Should compile
Actual behavior:
It throws an error for second last line:
Type '{ id: string; }' is not assignable to type 'Spec<T>'.
The compiler doesn't error on this:
I feel it is a bug but I may be misunderstanding something.
The text was updated successfully, but these errors were encountered: