Я пытаюсь использовать типы с условным отображением, чтобы получить только разрешающие ключи объекта определенного типа в качестве параметра функции.
Однако я сталкиваюсь с проблемой, заключающейся в том, что при этом не определяется правильный тип.
Я создал пример для демонстрации (просмотреть машинописный текст pl ayground):
interface TraversableType{
name: string;
}
interface TypeOne extends TraversableType{
typeNotTraversable: string;
typeTwo: TypeTwo;
typeThree: TypeThree;
}
interface TypeTwo extends TraversableType{
typeTwoNotTraversable: string;
typeOne: TypeOne;
typeThree: TypeThree;
}
interface TypeThree extends TraversableType{
typeThreeProp: string;
}
type TraversablePropNames<T> = { [K in keyof T]: T[K] extends TraversableType ? K : never }[keyof T];
//given start object, return
function indexAny<T extends TraversableType, K extends keyof T>(startObj: T, key: K): T[K] {
return startObj[key];
}
//same thing, but with only "traversable" keys allow
function indexTraverseOnly<T extends TraversableType, K extends TraversablePropNames<T>>(startObj: T, key: K): T[K] {
return startObj[key];
}
let t2: TypeTwo;
type keyType = keyof TypeTwo; // "typeTwoNotTraversable" | "typeOne" | "typeThree" | "name"
type keyType2 = TraversablePropNames<TypeTwo>; // "typeOne" | "typeThree"
let r1 = indexAny(t2, 'typeOne'); // TypeOne
let r2 = indexTraverseOnly(t2, 'typeOne'); // TypeOne | TypeThree
Обратите внимание, как при использовании K extends keyof T
функция indexAny
может определить правильный тип возвращаемого значения.
Однако, когда я пытаюсь использовать TraversablePropNames
тип условного сопоставления для определения ключа, он не знает, TypeOne
или TypeTwo
.
Есть ли способ написать функцию так, чтобы она разрешала ТОЛЬКО ключи TraversableType
И правильно определяла тип?
ОБНОВИТЬ:
Интересно ... кажется, работает 1 свойство в глубину, ЕСЛИ я оборачиваю метод в общий класс и передаю экземпляр (вместо первого параметра). Однако, похоже, он работает только для одного обхода ... затем он снова терпит неудачу:
class xyz<T>{
private traversable: T;
constructor(traversable: T) {
this.traversable = traversable;
}
indexTraverseOnly<K extends TraversablePropNames<T>>(key: K): T[K] {
return this.traversable[key];
}
indexTraverseTwice<K extends TraversablePropNames<T>, K2 extends TraversablePropNames<T[K]>>(key: K, key2: K2): T[K][K2] {
return this.traversable[key][key2];
}
}
let t2: TypeTwo;
let r3Obj = new xyz(t2);
let r3 = r3Obj.indexTraverseOnly('typeOne'); // TypeOne (WORKS!)
let r4 = r3Obj.indexTraverseTwice('typeOne', 'typeThree'); // TypeTwo | TypeThree