Как определить общий интерфейс для объекта с константами? - PullRequest
0 голосов
/ 05 ноября 2019

В проекте у меня есть несколько объектов со строковыми константами. Например:

export const Elements: Constants {
    DESCRIPTION: "DescriptionAutoField2",
    FORMULA_CALC: "FormulaCalcAutoField1",
    CHART_CODE: "ChartCodeAutoField1",
    CHART_CODE_DESCRIPTION: "ChartDescriptionAutoField1",
};

export const ChartAttr: Constants = {
    CHART: "Chart",
    CHART_DESCRIPTION: "ChartDescr",
};

export const SliceLink: Constants = {
    SLICE_CODE: "SliceCode",
    SLICE_DESC: "SliceDesc",
    SLICE_CALC: "SliceCalc",
};

Я определил интерфейс следующим образом, но в этом случае невозможно проверять KEY объекта во время компиляции.

 export interface Constants {
       [key: string]: string;
 }

Мой вопрос: как определить общий интерфейс "Константы""и иметь строгую компиляцию на основе определенных свойств объекта? Можно ли избежать «enum»?

1 Ответ

2 голосов
/ 05 ноября 2019

Не существует конкретного типа типа Constants, который бы соответствовал всем Elements, ChartAttr и SliceLink, в то время как одновременно запоминает точные ключи и значения каждого из них. Вместо этого вы можете представить универсальный тип , который соответствует вашему ограничению, и использовать вспомогательную функцию, чтобы гарантировать, что значения соответствуют ему, при выводе строго типизированного значения, которое запоминает отдельные типы ключей / значений:

// helper function
const asConstants = <S extends string, T extends Record<keyof T, S>>(
    c: T
): { readonly [K in keyof T]: T[K] } => c;

Я предположил, что вы хотите, чтобы константные свойства были помечены как readonly, и что тип каждого значения должен быть строковым литералом , а не просто string.

Теперьвы определяете свои константы с помощью функции вместо аннотации:

export const Elements = asConstants({
    DESCRIPTION: "DescriptionAutoField2",
    FORMULA_CALC: "FormulaCalcAutoField1",
    CHART_CODE: "ChartCodeAutoField1",
    CHART_CODE_DESCRIPTION: "ChartDescriptionAutoField1",
});

export const ChartAttr = asConstants({
    CHART: "Chart",
    CHART_DESCRIPTION: "ChartDescr",
});

export const SliceLink = asConstants({
    SLICE_CODE: "SliceCode",
    SLICE_DESC: "SliceDesc",
    SLICE_CALC: "SliceCalc",
});

Если вы проверяете типы Elements, ChartAttr и SliceLink с помощью IntelliSense вашей IDE, вы видите:

/*
const Elements: {
    readonly DESCRIPTION: "DescriptionAutoField2";
    readonly FORMULA_CALC: "FormulaCalcAutoField1";
    readonly CHART_CODE: "ChartCodeAutoField1";
    readonly CHART_CODE_DESCRIPTION: "ChartDescriptionAutoField1";
}

const ChartAttr: {
    readonly CHART: "Chart";
    readonly CHART_DESCRIPTION: "ChartDescr";
}

const SliceLink: {
    readonly SLICE_CODE: "SliceCode";
    readonly SLICE_DESC: "SliceDesc";
    readonly SLICE_CALC: "SliceCalc";
}
*/

И если вы попытаетесь передать неправильное значение в asConstants(), вы получите ошибку:

asConstants({
    NOT_A_STRING: 1, // error! number not a string        
})

Хорошо, надеюсь, это поможет. Удачи!

Ссылка на код

...