If you want to create a function that can unwrap an array type up to one level deep and then use conditional types with the result, you can achieve it like this:
// Unwrapping up to one level
type Unarray<T> = T extends Array<infer U> ? U : T;
// Example usage in a class
declare class Container<T> {
constructor(item: T);
public selectItem(fieldName: keyof Unarray<T>): void;
}
// Example interface
interface Person {
name: string,
age: number
}
declare const p1: Person;
declare const p2: Person;
const container = new Container(p1);
container.selectItem("name"); // works fine
const anotherContainer = new Container([p1, p2]);
anotherContainer.selectItem("age"); // works fine
anotherContainer.selectItem("push"); // error
This should fulfill your typing requirements. However, for actual implementation, you may need additional adjustments, as implementing conditional types usually involves some type assertions or overloads to satisfy the compiler. But based on your question, it seems you are interested in the typings rather than the implementation details.
In response to your additional query, yes, you can constrain T
to only accept array types by specifying it like so:
// Example class
declare class Box<T extends Array<any>> {
constructor(items: T);
public selectItem(fieldName: keyof (T[number])): void;
}
// Example interface
interface Person {
name: string,
age: number
}
declare const person1: Person;
declare const person2: Person;
const box1 = new Box(person1); // error
const box2 = new Box([person1, person2]);
box2.selectItem("age"); // works
In this case, I simplified the approach by removing conditional types altogether for clarity and simplicity of the code.