Как мне аннотировать тип параметра как «любое значение объекта»?

class ExampleClass {

    private static readonly MODES = {
        DEVELOPMENT: 0,
        PRODUCTION: 1,
        TEST: 2
    }

    //  Any Value of ExampleClass.MODES
    constructor(mode: MODE[?]) {

    }
}

В этом случае значения 0, 1, 2 не имеют смысла, если использовать enum, но насколько мне известно, мы не можем использовать enum как поле класса. Итак, давайте рассмотрим случай some value of object в этом вопросе.

0
Gurebu Bokofu 23 Окт 2018 в 14:08

2 ответа

Лучший ответ

Томаш был очень близок, но давайте дадим полный ответ. Чтобы получить тип значений typeof MODES, просто проиндексируйте его по типу всех его ключей.

type ValueOf<T> = T[keyof T];

// Prevent widening of the types of the constants to `number`.
function asLiterals<T extends number, U extends { [n: string]: T }>(arg: U) {
    return arg;
}

class ExampleClass {

    private static readonly MODES = asLiterals({
        DEVELOPMENT: 0,
        PRODUCTION: 1,
        TEST: 2
    });

    //  Any Value of ExampleClass.MODES
    constructor(mode: ValueOf<typeof ExampleClass.MODES>) {

    }
}
5
Matt McCutchen 24 Окт 2018 в 11:59

Вы можете использовать в этом конкретном случае type:

type myType = 'DEVELOPMENT' | 'PRODUCTION' | 'TEST'
class someClass {
  //  Any Value of ExampleClass.MODES
  constructor(mode: myType ) { }    
}

Для более сложных сценариев обратитесь к приведенной ниже документации TypeScript в форме фрагмента кода, где K extends keyof T используется для гарантии того, что в качестве аргументов функции передаются только значения, являющиеся частью спецификации объекта:

function pluck<T, K extends keyof T>(o: T, names: K[]): T[K][] {
  return names.map(n => o[n]);
}

interface Person {
    name: string;
    age: number;
}
let person: Person = {
    name: 'Jarid',
    age: 35
};
let strings: string[] = pluck(person, ['name']); // ok, string[]

Вышеупомянутые могут быть частью вашей служебной службы и универсально использоваться в нескольких конструкторах, типы которых вы хотите обеспечить.

Или даже заключите значения, которые вы хотите защитить, в отдельный класс и напрямую используйте keyof:

class A  {
    prop1: 1;
    prop2: 2;
}

class TestClass {
    constructor(key: keyof A) {

    }
}

let tc1 = new TestClass('prop1')
let tc2 = new TestClass('whoops') // Error

И насколько я понимаю ваше намерение, вы хотите иметь что-то больше вроде valueof, чем keyof. Если да, то да, перечисления и типы - это то, на что вам следует обратить внимание ИМХО.

1
Tomas 23 Окт 2018 в 11:55
52947545