Выводить общий тип в свойстве (как в функции) для правильной проверки типа - PullRequest
0 голосов
/ 18 апреля 2019

Я пытаюсь сделать вывод компилятора и проверить типы в универсальном свойстве.В частности, у меня есть:

type Args<T, O extends object> = {
    instance: O,
    key: { [K in keyof O]: T extends O[K] ? K : never }[keyof O]
};

class C<T> {
    public fn<O extends object>(args: Args<T, O>): void { }
}

Args - это объект и один из его ключей k, так что что-то типа T может быть присвоено k.Класс можно использовать следующим образом:

type Test = { a: string, b: number };
let test: Test = { a: "", b: 2 };
let c = new C<string>();

c.fn({ instance: test, key: "a" }); // works, as expected
c.fn({ instance: test, key: "b" }); // error, as expected

Это хорошо, поскольку выводится параметр типа O, проверяется тип key и при наборе текста предлагаются все возможности для key.

Теперь я хочу использовать объект Args, который можно использовать с C<T>.fn в качестве свойства в некоторых других классах (для целей внедрения), где тип O еще не известен.Однако проверка типа завершается неудачно с any:

interface I<T> {
    args: Args<T, any>;
}

let i: I<string>;
i = { args: { instance: test, key: "b" } }; // no error

Я попытался использовать лямбду вместо:

interface I2<T> {
    args: <O extends object>() => Args<T, O>;
}

let i2: I2<string>;
i2 = { args: () => ({ instance: test, key: "a" }) }; //Type 'Test' is not assignable to type 'O'. ???
c.fn(i.args);

Я не понимаю, почему возникает ошибка типа.

Как вы можете убедиться, что типы выводятся и проверяются для свойства интерфейса, как это работает для универсальной функции?

1 Ответ

0 голосов
/ 19 апреля 2019

Таким образом, поскольку это невозможно, практический подход заключается в использовании установщика или фабрики, которая применяет ограничения типа. E.g.:

type Thing<T, A> = {
    a: A,
    b: SomeTypeDependingoOn<A>
};
class Factory<T> {
    public getThing<A, B extends SomeTypeDependingoOn<A>>(a: A, b: B): Thing<T, A>{
        return { a: a, b: b };
    }
}
let thing: Thing<string, any>;
thing = new Factory<string>().getThing(...); // type checking
...