I am trying to get type inheritance for an array of objects where one of the object value types should be inheriting types from another object value. I have my doubts if this is possible but it's worth a shot. Right now I think my best bet is to use an object instead of an array an solve it like that.
The example is based on the answer of someone asking something similar.
All the way at the bottom of the example 1, it does not give an error for the object key 'y'. This should give an error as it's not in initialValue.inherit object.
// Example 1
type FinalValues<T extends Array<{ initialValue: { inherit: any } }>> = {
[P in keyof T]: T[P] extends { initialValue: infer I extends { inherit: any } } ? { initialValue: I, finalValue: I['inherit'] }: never
}
function myFunc<T extends [{ initialValue: { inherit: any } }] | Array<{ initialValue: { inherit: any } }>>(v: T & FinalValues<T>) {
}
myFunc([
{
initialValue: { inherit: { x: 6 } }, // number
finalValue: { x: 6 }, // number
},
{
initialValue: { inherit: { y: "hello" } }, // string
finalValue: { y: "bye" }, // string
},
]);
myFunc([
{
initialValue: { inherit: { x: "hello" , y: 1} }, // string/number
finalValue: { x: 6, y: 1 }, // err (x should be a string)
},
{
initialValue: { inherit: { a: 'hello' } }, // string
finalValue: { a: 6, }, // err (a should be a string)
},
{
initialValue: { inherit: { z: 'hello' } }, // string
finalValue: { y: 1, z: 'hello' }, // this doesnt error but it should (y is not in initialValue.inherit)
},
]);
// Example 2
interface TypeOne {
options: { someBool?: boolean; someString: string };
}
interface TypeTwo {
options: { otherKeyBool: boolean };
}
const exampleOne: TypeOne = {
options: { someBool: true, someString: 'hello' },
};
const exampleTwo: TypeTwo = { options: { otherKeyBool: true } };
interface PassedOptionsType {
options: Record<string, number | boolean | string>;
}
type ConsumerArrayType<T extends PassedOptionsType[]> = {
[K in keyof T]: {
passedOptions: T[K];
typedBasedOn: T[K]["options"];
};
};
const consumerFn = <T extends PassedOptionsType[]>(arr: ConsumerArrayType<T>) => null;
consumerFn([
{
passedOptions: exampleOne,
typedBasedOn: {
// is valid:
someString: 'valid string',
// errors correctly:
unknownKey: 'bla', // invalid key
},
},
{
passedOptions: exampleTwo,
typedBasedOn: {
// is valid:
otherKeyBool: true,
// is NOT working as expected as its an object key
// of exampleOne.options and not of exampleTwo.options
// this should give an type error
someString: 'invalid type',
},
},
]);