簡體   English   中英

如何在打字稿中創建字符串的子類型

[英]How to make a subtype of string in typescript

我使用 typescript 和 react hooks 制作了一個名為 risk 的游戲。 游戲是在某種地圖上進行的。 所以首先我有設計我MapEditor 地圖編輯器的狀態就像

export interface IMapEditorState {
   mousePos: IPoint;
   countries: {[k: string]: ICountry};
   continents: { [k: string]: IContinent };
}

countriescontinents是對象。 國家的界面看起來像

//The "name" property and above key will be same in `{[k: string]: ICountry};` will be same
export interface ICountry {
   name: string;
   border: IDot[];
   neighbours: string[];
   completed: boolean;
}

現在我做了一個減速器功能。 對於所有類型的動作,我使用了兩個道具namedata name將始終是一個string ,數據將取決於name的類型

type ActionTypes = {name: "removeCountry", data: string} | {name: "addCountry", data: ICountry};
const reducer = (state: IMapEditorState, action: ActionTypes) => {
   ...
}

現在查看ActionTypes的第一個類型,它是{name: "removeCountry", data: string} 在調度方法 a 中,我將使用{name: "removeCountry"}編譯器將強制將data作為string傳遞,但它不能是我不想要的任何字符串。 我想,我應該只能夠通過字符串這是關鍵的{[k: string]: ICountry}IMapEditorStatenameICountry

有什么方法可以創建一個名為CountryName的字符串的子類型並使用它

export interface IMapEditorState {
   mousePos: IPoint;
   countries: {[k: CountryName]: ICountry};
   continents: { [k: string]: IContinent };
}
export interface ICountry {
   name: CountryName;
   border: IDot[];
   neighbours: string[];
   completed: boolean;
}
type ActionTypes = {name: "removeCountry", data: CountryName} | {name: "addCountry", data: ICountry};

如果你能幫助我,我將非常感謝,如果你知道什么是游戲,請對我的數據結構發表你的看法。

如果您希望能夠在編譯時進行這些檢查,則必須列出所有可能的國家/地區名稱:

type CountryName = 'cName1' | 'cName2' | 'cName3';

或者,如果您可以定義所有可能國家/地區的初始對象,則可以將其聲明為const (以便 TS 不會概括其字符串),然后通過keyof獲取其鍵:

const initialCountries = {
    cName1: {
        name: 'cName1',
        completed: false
        // ...
    },
    cName2: {
        name: 'cName2',
        completed: false
    },
    cName3: {
        name: 'cName3',
        completed: false
    },
} as const;
type CountryName = keyof typeof initialCountries;

CountryName結果是"cName1" | "cName2" | "cName3" "cName1" | "cName2" | "cName3" "cName1" | "cName2" | "cName3"

然后你可以使用上面的CountryName定義IMapEditorState

export interface ICountry {
    name: CountryName;
    border: IDot[];
    neighbours: string[];
    completed: boolean;
}
export interface IMapEditorState {
    mousePos: IPoint;
    countries: { [k: CountryName]: ICountry };
    continents: { [k: string]: IContinent };
}

然后將編譯以下內容:

const initalIMapEditorState: IMapEditorState = {
    countries: initialCountries,
    // ...
};

然后您可以在任何其他需要的地方使用CountryName

type ActionTypes = {name: "removeCountry", data: CountryName} | {name: "addCountry", data: ICountry};

打字稿 4.1.5:

在我的情況下,我需要將這種格式“YYYY-MM-DD”的字符串化日期標記為 ISODate 而不僅僅是字符串。 我使用了這種方法,如果有效字符串的數量不止幾個,我認為它比這個答案更有效:

interface ISODateDifferentiator extends String {
  [key: string]: unknown;
}
export type ISODate = ISODateDifferentiator & string; 

export const ValidateIsoDate = (date: string): date is ISODate => {
  return date.match(/^\d{4}-\d{2}-\d{2}$/) !== null;
} 

您得到所需的Type 'string' is not assignable to type 'ISODate'. 當進行不安全的賦值但可以使用 typeguard 函數進行轉換時。 您還可以獲得字符串方法自動完成。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM