In the following code (Playground) I try to make autocompletion and function signature inference work within personTypeX({...}) at the same time but I can only achieve either of these but not both.
Is it even possible?
Here are the requirements:
- If a person (= the input) has a
firstName, then it must be astring. - If a person has an
age, then it must be anumber. - ...
- If a person has a property which is neither
firstName,lastName,age,favouriteFoodnorgetLegCountthen the value at that property must itself be aPerson.
There are 3 overall additional requirements
- Invalid input must be detected (at any level in the input) and marked in the correct location.
see below: works with
personType1()andpersonType2() - Autocompletion for all keys in
firstName, ...,getLegCountmust be provided withinpersonTypeX({})see below: currently only works withinpersonType2({}) - If the key (here only
getLegCount) enforces its value to be a function, then the function signature must be correctly inferred see below: currently only works withinpersonType1({})
type FixedType = {
firstName: string,
lastName: string,
age: number,
favouriteFood: string[],
getLegCount: (numHeads: number) => number,
};
type PersonType<T> = {
[K in (keyof T | keyof FixedType)]?:
K extends keyof FixedType
? FixedType[K]
: K extends keyof T
? T[K] extends object
? PersonType<T[K]>
: PersonType<{}>
: never
}
// ---- ---- ---- ---- ----
function personType1<T extends PersonType<T>>(t: T) { // signature version 1
return t;
}
const person11 = personType1({
firstName: 'Mark',
lastName: 'Antony',
holger: {
age: 12,
paul: {
// <-- type 'a' for autocompletion of 'age' => NOT WORKING
favouriteFood: ['cheese'],
firstName: 'Paul',
getLegCount: (numHeads) => 2, // <-- hover over 'numHeads' => numHeads: number correctly inferred => WORKING
}
},
});
// ----
function personType2<T extends PersonType<T>>(t: T & PersonType<T>) { // signature version 2
return t;
}
const person1 = personType2({
firstName: 'Mark',
lastName: 'Antony',
holger: {
age: 12,
paul: {
// <-- type 'a' for autocompletion of 'age' => WORKING
favouriteFood: ['cheese'],
firstName: 'Paul',
getLegCount: (numHeads) => 2, // <-- hover over 'numHeads' => numHeads: any inferred => NOT WORKING
// that's probably bc it's the most common signature for
// (property) getLegCount: ((numHeads: any) => number) & ((numHeads: number) => number)
// but I have no clue how to fix this
}
},
});
