如何在TypeScript中處理日期字符串
前言:
在我最近的一個(gè)項(xiàng)目中,我必須去處理多個(gè)自定義的日期字符串表示法,比如YYYY-MM-DD和YYYYMMDD。由于這些日期是字符串變量,TypeScript默認(rèn)會(huì)推斷成為string類型。雖然這在技術(shù)實(shí)現(xiàn)上沒有錯(cuò),但是在工作中使用這樣的類型定義是很寬泛的,使得有效處理這些日期字符串變得很困難。例如,let dog = 'alfie'也被推斷為一個(gè)string類型。
在這篇文章中,我會(huì)將我的解決方法呈現(xiàn)給你,通過輸入這些日期字符串來改善開發(fā)者的體驗(yàn)并減少潛在的錯(cuò)誤。
在進(jìn)入編碼之前,讓我們簡單回顧下實(shí)現(xiàn)目標(biāo)需求要利用到的typescript特性,即模板字面量類型和通過類型謂詞縮小范圍。
一、模板字面量類型
在typescript4.1版本中引入,模板字面量類型和JavaScript的模板字符串語法相同,但是是作為類型使用。模板字面量類型解析為一個(gè)給定模板的所有字符串組合的聯(lián)合。這聽起來可能有點(diǎn)抽象,
直接看代碼:
type Person = 'Jeff' | 'Maria'
type Greeting = `hi ${Person}!` // Template literal type
const validGreeting: Greeting = `hi Jeff!` //
// note that the type of `validGreeting` is the union `"hi Jeff!" | "hi Maria!`
const invalidGreeting: Greeting = `bye Jeff!` //
// Type '"bye Jeff!"' is not assignable to type '"hi Jeff!" | "hi Maria!"模板字面量類型非常強(qiáng)大,允許你對這些類型進(jìn)行通用類型操作。例如,大寫字母化。
type Person = 'Jeff' | 'Maria'
type Greeting = `hi ${Person}!`
type LoudGreeting = Uppercase<Greeting> // Capitalization of template literal type
const validGreeting: LoudGreeting = `HI JEFF!` //
const invalidGreeting: LoudGreeting = `hi jeff!` //
// Type '"hi Jeff!"' is not assignable to type '"HI JEFF!" | "HI MARIA!"二、類型謂詞縮小范圍
typescript在縮小類型范圍方面表現(xiàn)得非常好,可以看下面這個(gè)例子:
let age: string | number = getAge();
// `age` is of type `string` | `number`
if (typeof age === 'number') {
// `age` is narrowed to type `number`
} else {
// `age` is narrowed to type `string`
}也就是說,在處理自定義類型時(shí),告訴typescript編譯器如何進(jìn)行類型縮小是有幫助的。例如,當(dāng)我們想在執(zhí)行運(yùn)行時(shí)驗(yàn)證后縮小到一個(gè)類型時(shí),在這種情況下,類型謂詞窄化,或者用戶定義的類型守護(hù),就可以派上用場。
在下面這個(gè)例子中,isDog類型守護(hù)通過檢查類型屬性來幫助縮小animal變量的類型:
type Dog = { type: 'dog' };
type Horse = { type: 'horse' };
// custom type guard, `pet is Dog` is the type predicate
function isDog(pet: Dog | Horse): pet is Dog {
return pet.type === 'dog';
}
let animal: Dog | Horse = getAnimal();
// `animal` is of type `Dog` | `Horse`
if (isDog(animal)) {
// `animal` is narrowed to type `Dog`
} else {
// `animal` is narrowed to type `Horse`
}三、定義日期字符串
為了簡潔起見,這個(gè)例子只包含YYYYMMDD日期字符串的代碼。
首先,我們需要定義模板字面量類型來表示所有類似日期的字符串的聯(lián)合類型
type oneToNine = 1|2|3|4|5|6|7|8|9
type zeroToNine = 0|1|2|3|4|5|6|7|8|9
/**
* Years
*/
type YYYY = `19${zeroToNine}${zeroToNine}` | `20${zeroToNine}${zeroToNine}`
/**
* Months
*/
type MM = `0${oneToNine}` | `1${0|1|2}`
/**
* Days
*/
type DD = `${0}${oneToNine}` | `${1|2}${zeroToNine}` | `3${0|1}`
/**
* YYYYMMDD
*/
type RawDateString = `${YYYY}${MM}${DD}`;
const date: RawDateString = '19990223' //
const dateInvalid: RawDateString = '19990231' //31st of February is not a valid date, but the template literal doesnt know!
const dateWrong: RawDateString = '19990299'// Type error, 99 is not a valid day從上面的例子可以得知,模板字面量類型有助于指定日期字符串的格式,但是沒有對這些日期進(jìn)行實(shí)際驗(yàn)證。因此,編譯器將19990231標(biāo)記為一個(gè)有效的日期,即使它是不正確的,只因?yàn)樗夏0宓念愋汀?/p>
另外,當(dāng)檢查上面的變量如date、dateInvalid、dateWrong時(shí),你會(huì)發(fā)現(xiàn)編輯器會(huì)顯示這些模板字面的所有有效字符的聯(lián)合。雖然很有用,但是我更喜歡設(shè)置名義類型,使得有效的日期字符串的類型是DateString,而不是"19000101" | "19000102" | "19000103" | ...。在添加用戶定義的類型保護(hù)時(shí),名義類型也會(huì)派上用場。
type Brand<K, T> = K & { __brand: T };
type DateString = Brand<RawDateString, 'DateString'>;
const aDate: DateString = '19990101'; //
// Type 'string' is not assignable to type 'DateString'為了確保我們的DateString類型也代表有效的日期,我們將設(shè)置一個(gè)用戶定義的類型保護(hù)來驗(yàn)證日期和縮小類型
/**
* Use `moment`, `luxon` or other date library
*/
const isValidDate = (str: string): boolean => {
// ...
};
//User-defined type guard
function isValidDateString(str: string): str is DateString {
return str.match(/^\d{4}\d{2}\d{2}$/) !== null && isValidDate(str);
}現(xiàn)在,讓我們看看幾個(gè)例子中的日期字符串類型。在下面的代碼片段中,用戶定義的類型保護(hù)被應(yīng)用于類型縮小,允許TypeScript編譯器將類型細(xì)化為比聲明的更具體的類型。然后,在一個(gè)工廠函數(shù)中應(yīng)用了類型保護(hù),以從一個(gè)未標(biāo)準(zhǔn)化的輸入字符串中創(chuàng)建一個(gè)有效的日期字符串。
/**
* Usage in type narrowing
*/
// valid string format, valid date
const date: string = '19990223';
if (isValidDateString(date)) {
// evaluates to true, `date` is narrowed to type `DateString`
}
// valid string format, invalid date (February doenst have 31 days)
const dateWrong: string = '19990231';
if (isValidDateString(dateWrong)) {
// evaluates to false, `dateWrong` is not a valid date, even if its shape is YYYYMMDD
}
/**
* Usage in factory function
*/
function toDateString(str: RawDateString): DateString {
if (isValidDateString(str)) return str;
throw new Error(`Invalid date string: ${str}`);
}
// valid string format, valid date
const date1 = toDateString('19990211');
// `date1`, is of type `DateString`
// invalid string format
const date2 = toDateString('asdf');
// Type error: Argument of type '"asdf"' is not assignable to parameter of type '"19000101" | ...
// valid string format, invalid date (February doenst have 31 days)
const date3 = toDateString('19990231');
// Throws Error: Invalid date string: 19990231總結(jié):
我希望這篇文章能讓我們了解TypeScript在輸入自定義字符串方面的能力。請記住,這種方法也適用于其他自定義字符串,如自定義user-ids、user-xxxx,以及其他日期字符串,像YYYY-MM-DD。
當(dāng)結(jié)合用戶定義的類型防護(hù)、模板字面字符串和名義類型時(shí),可能性是無窮的。
到此這篇關(guān)于如何在TypeScript中處理日期字符串的文章就介紹到這了,更多相關(guān)TypeScript處理字符串內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
javascript forEach函數(shù)實(shí)現(xiàn)代碼
在Base2中找到一個(gè)叫forEach的函數(shù),是我見過的最好的實(shí)現(xiàn)。挖出來分析一下。它能對各種普通對象,字符串,數(shù)組以及類數(shù)組進(jìn)行遍歷。如果原游覽器的對象已實(shí)現(xiàn)此函數(shù),它則調(diào)用原對象的函數(shù)。2010-01-01
uni-app禁用返回按鈕/返回鍵的具體實(shí)現(xiàn)
今天在使用uni-app開發(fā)登錄頁面時(shí)遇到一個(gè)需求,需要禁用返回按鈕,下面這篇文章主要給大家介紹了關(guān)于uni-app禁用返回按鈕/返回鍵的具體實(shí)現(xiàn),需要的朋友可以參考下2022-11-11
js數(shù)組常用19種方法(你會(huì)的到底有多少呢)
這篇文章主要給大家介紹了關(guān)于js數(shù)組常用19種方法,大家可以看看你會(huì)的到底有多少呢,在日常開發(fā)中我們會(huì)接觸到j(luò)s中數(shù)組的一些方法,需要的朋友可以參考下2023-09-09
javascript Array.sort() 跨瀏覽器下需要考慮的問題
最近組里項(xiàng)目需要一個(gè)簡單的Table排序的功能,這個(gè)功能實(shí)現(xiàn)起來很簡單,并且網(wǎng)上也有很多現(xiàn)成的代碼,因此任務(wù)很快完成。2009-12-12
詳解js如何優(yōu)雅處理后端返回的單元格數(shù)據(jù)
這篇文章主要為大家詳細(xì)介紹了JavaScript如何優(yōu)雅處理后端返回的單元格數(shù)據(jù),文中的示例代碼講解詳細(xì),有需要的小伙伴可以跟隨小編一起學(xué)習(xí)一下2023-10-10
打造通用的勻速運(yùn)動(dòng)框架(實(shí)例講解)
下面小編就為大家?guī)硪黄蛟焱ㄓ玫膭蛩龠\(yùn)動(dòng)框架(實(shí)例講解)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-10-10

