34
loading...
This website collects cookies to deliver better user experience
number
type but a literal representation.const foo = <T,>(a: T) => a
// const foo: <42>(a: 42) => 42
foo(42)
T
generic parameter was infered to 42
which is perfectly fine.{a: 42}
:const foo = <T,>(a: T) => a
// const foo: <{ a: number; }> (a: { a: number; }) => { a: number; }
foo({ a: 42 })
{a: 42}
, not just {a: number}
.as const
.foo({ a: 42 })
const foo = <Value, T extends { a: Value }>(a: T) => a
// const foo: <{ a: number; }> (a: { a: number; }) => { a: number; }
foo({ a: 42 })
Value
generic.const foo = <Value extends number, T extends { a: Value }>(a: T) => a
// const foo: <{ a: 42; }> (a: { a: 42; }) => { a:42; }
foo({ a: 42 })
const foo = <
Key extends PropertyKey,
Value extends number | string,
T extends Record<Key, Value>
>(a: T) => a
// const foo: <PropertyKey, string | number, { a: 42; b: "hello";}>
foo({ a: 42, b: 'hello' })
string | number
as a value type, we can use Json
type.type Json =
| null
| string
| number
| boolean
| Array<JSON>
| {
[prop: string]: Json
}
const foo = <
Key extends PropertyKey,
Value extends Json,
T extends Record<Key, Value>
>(a: T) => a
// const foo: <PropertyKey, Json, { a: 42; b: "hello"; }
foo({ a: 42, b: 'hello' })
type Json =
| null
| string
| number
| boolean
| Array<JSON>
| {
[prop: string]: Json
}
const foo = <
Key extends PropertyKey,
Value extends Json,
T extends Record<Key, Value>[]
>(a: T) => a
// const foo: <PropertyKey, Json, { a: 42; b: "hello"; }
foo([{ a: 42, b: 'hello' }])
const foo = <
V extends number,
A extends { a: V }[]
>(a: [...A]) => a
foo([{ a: 1 }])
1
.const fn = <T,>(
arg: {
a: (a_arg: number) => T;
b: (b_arg: T) => void
}
) => null;
fn({
a: (arg1) => ({ num: 0 }),
b: (arg2 /** unknown */) => {
arg2.num;
}, // Error
});
b
method/callback/function should have return type of a
. But, TS infers it as unknown
.My question is based on this question and answer
Let's say we have next code:
const myFn = <T,>(p: {
a: (n: number) => T
b: (o: T) => void,
}) => {
// ...
}
myFn({
a: () => ({ n: 0 }), // Parameter of a is ignored
…
const myFn = <T,>(arg: {
a: (a_arg: number) => T;
b: <U extends T>(b_arg: U) => void;
}) => {
// ...
};
myFn({
a: (a) => ({ num: 0 }),
b: (b_arg) => {
b_arg.num;
}, // Works!
});
class Store<T> {
itemCreator<U>(
generate: (item: Omit<T, keyof U>) => U
): (item: Omit<T, keyof U>) => Omit<T, keyof U> & U {
return item => ({...item, ...generate(item)});
}
}
type Person = {
id: string;
name: string;
email: string;
age?: number;
};
const create = new Store<Person>()
.itemCreator(() => ({id: 'ID', extra: 42}));
const person = create({name: 'John', email: '[email protected]'});
itemCreator
callback.const create = new Store<Person>()
.itemCreator((a) => ({id: 'ID', extra: 42}));
const person = create({name: 'John', email: '[email protected]'}); // error
Omit<T, keyof U>
outside the function:class Store<T> {
itemCreator<U>(
// here I have used extra generic with default value
generate: <P = Omit<T, keyof U>>(item: P) => U
): (item: Omit<T, keyof U>) => Omit<T, keyof U> & U {
return item => ({ ...item, ...generate(item) });
}
}
type Person = {
id: string;
name: string;
email: string;
age?: number;
};
const create = new Store<Person>()
.itemCreator((a) => ({id: 'ID', extra: 42}));
const person = create({name: 'John', email: '[email protected]'}); // ok
TypeScript Version: 2.9
Search Terms: function parameter inference
Code
interface MyInterface<T> {
retrieveGeneric: (parameter: string) => T,
operateWithGeneric: (generic: T) => string
}
const inferTypeFn = <T>(generic: MyInterface<T>) => generic;
// inferred type for myGeneric = MyInterface<{}>, `generic.toFixed()` marked as error (as {} doesn't have .toFixed())
const myGeneric = inferTypeFn({
retrieveGeneric: parameter => 5,
operateWithGeneric: generic => generic.toFixed()
});
// inferred type for myGeneric = MyInterface<number>, everything OK
const myWorkingGeneric = inferTypeFn({
retrieveGeneric: (parameter: string) => 5,
operateWithGeneric: generic => generic.toFixed()
});
Expected behavior:
myGeneric
has every type correctly inferred, parameter
is a string, generic
is a number.
Actual behavior:
it doesn't infer the correct type for generic
parameter unless you manually specify the type of parameter
(which it already had the right type)