簡體   English   中英

在 TypeScript 中,我可以指定 object 字段的類型,同時仍能推斷出文字鍵類型嗎?

[英]In TypeScript, can I specify the type of object fields while still getting the literal key types inferred?

我要做的是定義某種“豐富的枚舉”,其中每個枚舉鍵都鏈接到我想指定其類型的一些數據。

例如,像這樣:

const Seasons = {
    winter: { temperature: 5, startMonth: "December" },
    spring: { temperature: 20, startMonth: "March" },
    summer: { temperature: 30, startMonth: "June" },
    fall: { temperature: 15, startMonth: "September" },
} as const

這個聲明很好,讓我可以做如下事情:

type Season = keyof typeof Seasons // "winter" | "spring" | "summer" | "fall"

甚至像

function isSeason(s: string): s is Season {
    return Object.keys(Seasons).includes(s)
}

但是,我不能做的是讓編譯器檢查所有“季節定義”是否具有給定的類型。 如果我定義這個:

type SeasonData = typeof Seasons[Season]

然后SeasonData是所有定義類型的並集——無論它們是否具有相同的形狀。

因此,我正在尋找一種語法上非冗余且輕便的方式來定義以下內容:

const Seasons: EnumWith<{temperature: number, startMonth: string}> = ... // as before
               ^^^^^^^^ <- to be defined!

特別是,我試圖不必在任何其他結構(接口或數組)中重復季節列表,並直接從 object 定義推斷類型Season (盡管聽到替代總是好的。)。

可以做些什么?

我不確定我是否完全理解您的用例,我會 model 的方式您的類型之間的關系類似於以下內容

type Season =
  | "winter"
  | "spring"
  | "summer"
  | "fall"

type Month =
  | "January"
  | "February"
  | "March"
  | "April"
  | "May"
  | "June"
  | "July"
  | "August"
  | "September"
  | "October"
  | "November"
  | "December"

type SeasonStruct = {
  temperature: number
  startMonth: Month
}

type Seasons = { [K in Season]: SeasonStruct }

const seasons: Seasons = {
    winter: { temperature: 5, startMonth: "December" },
    spring: { temperature: 20, startMonth: "March" },
    summer: { temperature: 30, startMonth: "June" },
    fall:   { temperature: 15, startMonth: "September" },
}

這應該為您提供足夠的構建塊來代表您在域中需要的所有內容,希望對您有所幫助。

剛剛找到了一種有點復雜的方法來從鍵中提取文字類型信息,同時仍然檢查值:

function EnumWith<P>() {
    return function <K extends keyof any, R extends Record<K, P>>(defs: R): R {
        return defs
    }
}

這允許這樣寫:

const Seasons = EnumWith<{
    temperature: number
    startMonth: Month // defined as in bugs's answer
}>()({
    winter: { temperature: 5, startMonth: "December" },
    spring: { temperature: 20, startMonth: "March" },
    summer: { temperature: 30, startMonth: "June" },
    fall: { temperature: 15, startMonth: "September" },
})
type Season = keyof typeof Seasons

關鍵是要發現K extends keyof any可以讓你在泛型簽名中捕獲鍵的類型,並將這兩種泛型類型划分為兩個 function 調用,以便我們可以指定一個並推斷另一個(目前不可能在 TypeScript 中的單個 function 調用中)。

所以,當然,這行}>()({有點礙眼……

暫無
暫無

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

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