I'm exploring the concept of type inheritance for an array of objects, where one object's value types should inherit from another. While I'm unsure if this is achievable, it's definitely worth a try. Currently, I believe my best approach would be to use an object instead of an array and work through it that way.
This example is based on a similar question asked by someone else.
In Example 1, towards the end, there's a discrepancy with the object key 'y'. It doesn't throw an error even though it's not part of the 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',
},
},
]);