[英]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 };
}
countries
和continents
是對象。 國家的界面看起來像
//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;
}
現在我做了一個減速器功能。 對於所有類型的動作,我使用了兩個道具name
和data
。 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}
在IMapEditorState
或name
中ICountry
。
有什么方法可以創建一個名為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.