![](/img/trans.png)
[英]Convert specific types of values in an object to another type in TypeScript
[英]Is there a way to use specific values of an object type when creating another object type
該示例用於定義QuestionMap
和AnswerMap
。 有多種類型的問題會產生不同類型的答案。 所以,為了定義答案的 map,你必須知道這個問題。 這是一個例子:
const questionMap: QuestionMap = {
QUESTION_1: { type: 'boolean' },
QUESTION_2: { type: 'string' }
QUESTION_3: { type: 'dropdown', options: { CUSTOM: 'custom answer', UNUSED: 'unused answer' }}
}
const answerMap: Answer<QuestionMap> = {
QUESTION_1: true,
QUESTION_2: 'custom answer'
}
在對AnswerMap
類型的最佳嘗試中,它不會將Answer
類型用於特定問題。
type AnswerMap<TQuestionMap extends QuestionMap> = Partial<Record<QuestionId, Answer<TQuestionMap[QuestionId]>>>
根據問題類型正確鍵入每個答案的AnswerMap
的正確定義是什么?
我要猜測您的QuestionMap
類型...好吧,實際上我要消除它,因為它對我的回答沒有多大幫助。 首先,如果您想強制answerMap
對應於 questionMap 中的特定questionMap
,則根本不應該注釋questionMap
。 這樣做最終會將questionMap
的類型擴大到完全忘記這些細節的東西,就像說const str: string = "hello"
會忘記str
是字符串文字"hello"
並且只記住它是一個string
.
事實上,我建議不要使用注釋,而是使用const
斷言,以便編譯器跟蹤其中的每個字符串文字:
const questionMap = {
QUESTION_1: { type: 'boolean' },
QUESTION_2: { type: 'string' },
QUESTION_3: { type: 'dropdown', options: { CUSTOM: 'custom answer', UNUSED: 'unused answer' } }
} as const;
如果您檢查questionMap
的類型,您會明白我的意思:
/* const questionMap: {
readonly QUESTION_1: {
readonly type: "boolean";
};
readonly QUESTION_2: {
readonly type: "string";
};
readonly QUESTION_3: {
readonly type: "dropdown";
readonly options: {
readonly CUSTOM: "custom answer";
readonly UNUSED: "unused answer";
};
};
} */
所以現在編譯器對questionMap
有足夠的了解來處理它。 但是應該做什么處理呢?
我將假設您有一些“簡單”問題類型,其中問題被指定為{type: "someString"}
並且答案是取決於"someString"
的單一類型。 讓我們告訴編譯器它們:
type SimpleQuestionTypes = {
boolean: boolean;
string: string;
number: number;
}
然后我要說Question
類型要么是其中之一,要么是需要指定一些options
的"dropdown"
類型:
type Question = { type: keyof SimpleQuestionTypes } | { type: "dropdown", options: any };
這對於您的用例可能不夠嚴格,並且您可能還有其他問題類型,但這至少對於您的示例代碼應該足夠了。
好的,現在讓我們弄清楚如何將類型T
擴展Question
並將其轉換為預期的答案類型:
type Answer<T extends Question> =
T['type'] extends keyof SimpleQuestionTypes ? SimpleQuestionTypes[T['type']] :
'options' extends keyof T ? T['options'][keyof T['options']] :
never;
如果T
具有對應於其中一種簡單問題類型的type
屬性,我們將只從SimpleQuestionTypes
中讀取答案類型。 否則,如果有options
屬性,我們將獲取該options
屬性的所有屬性值類型的並集。
最后, AnswerMap
只是將Answer
計算映射到 object 的每個屬性上:
type AnswerMap<T extends Record<keyof T, Question>> = {
[K in keyof T]: Answer<T[K]>
} // extends infer O ? { [K in keyof O]: O[K] } : never;
// uncomment the above if you want to see easier-to-read output types
現在, answerMap
的類型應該是AnswerMap<typeof questionMap>
,我們在這里使用 TypeScript typeof
類型查詢運算符來獲取確切類型的questionMap
。 像這樣:
const answerMap: AnswerMap<typeof questionMap> = {
QUESTION_1: true,
QUESTION_2: 'str',
QUESTION_3: 'custom answer'
}
順便說一句,如果我們檢查這個類型,它相當於如下:
/* const answerMap: {
readonly QUESTION_1: boolean;
readonly QUESTION_2: string;
readonly QUESTION_3: "custom answer" | "unused answer";
} */
這大概就是你想要的。 為了確定起見,讓我們看看當您為answerMap
提供錯誤值時會發生什么失敗:
const badAnswerMap1: AnswerMap<typeof questionMap> = { // error!
QUESTION_1: true,
QUESTION_2: 'str',
}; // Property 'QUESTION_3' is missing
const badAnswerMap2: AnswerMap<typeof questionMap> = {
QUESTION_1: true,
QUESTION_2: 'str',
QUESTION_3: 'custom answer',
QUESTION_4: 'str' // error! object literal may only specify known properties
}
const badAnswerMap3: AnswerMap<typeof questionMap> = {
QUESTION_1: "oops", // error! string is not assignable to boolean
QUESTION_2: 'str',
QUESTION_3: 'custom answer',
}
const badAnswerMap4: AnswerMap<typeof questionMap> = {
QUESTION_1: true,
QUESTION_2: 'str',
QUESTION_3: 'custom anwser', // error! "custom anwser" is not assignable to "custom answer" | "unused answer"
}
在我看來是對的。 希望這足以幫助您繼續進行實際用例。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.