[英]Generics in typescript - not assignable to type / parameter of type
我有以下兩個服務調用,它們都使用方法 ConcertDates()。
private callMyFirstService(params: MyParams): Observable<MyDto> {
return this.http.post<MyDto>(params).pipe(map(response => this.convertDates<MyDto>(response)));
}
private callMySecondService(params: MyOtherParams): Observable<MyAnotherDto> {
return this.http.post<MyAnotherDto>(params).pipe(map(response => this.convertDates<MyAnotherDto>(response)));
}
由於這些方法與另一種類型的 dto 一起運行,因此我嘗試實現一些在這兩種情況下都可以調用的通用函數。 我有類似的東西:
private convertDates<type>(input: type): type {
for (const key in input) {
if (!input.hasOwnProperty(key)) {
continue;
}
if (typeof input[key] === 'object') {
this.convertDates(input[key]);
} else if (typeof input[key] === 'string' && this.MY_REGEXP.test(input[key])) {
input[key] = new Date(input[key]);
}
}
return input;
}
這似乎不起作用,因為我總是得到:
Type 'Date' is not assignable to type 'type[Extract<keyof type, string>]'
和...
Argument of type 'type[Extract<keyof type, string>]' is not assignable to parameter of type 'string'.
Type 'type[string]' is not assignable to type 'string'.
有任何想法嗎? 提前非常感謝!
無論該type
是什么類型,都具有特定的形狀。 您似乎期待 object 具有一些字符串屬性,而您將其更改為Date
。 這意味着您違反了該類型。
或者更簡單地說:
const obj = { maybeDate: 'foo' } // type is { maybeDate: string }
obj.maybeDate = new Date() // error
maybeDate
的類型是string
,因此您不能只將Date
分配給該插槽。 這違反了類型。
通常在進行這樣的轉換時,您需要將 object 轉換為中間類型,然后將其轉換為最終類型。
const obj = { maybeDate: 'foo' } // type is { maybeDate: string }
const objIntermediate = obj as { maybeDate: string | Date }
objIntermediate.maybeDate = new Date()
const objFinal = objIntermediate as { maybeDate: Date }
在這一點上,重要的是要說你的邏輯是不可能輸入的。 首先,因為 typescript 不支持正則表達式轉換,但更重要的是類型系統無法知道是否應將string
轉換為日期,因為它不會提前知道該字符串的內容。
interface MyDto {
name: string
createdAt: string // How could typescript possible know this is a date string?
}
我以不同的方式在自己的代碼庫中解決了問題。 我鍵入Dto
以使字段為Date
,例如:
interface MyDto {
name: string
createdAt: Date
}
然后使用一些自定義 JSON 解碼器邏輯來更改字段:
/** Parse JSON content from a response. If any string matches the ISO date time format, convert it to a Date. */
async function decodeJson(res: Response): Promise<any> {
return JSON.parse(await res.text(), (key: string, value: unknown) => {
if (typeof value === 'string' && dateFormat.test(value)) {
return new Date(value)
}
return value
})
}
const dateFormat = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/
由以下人員調用:
function fetchStuff<T>(path: string) {
const res = await window.fetch(path)
const json = await decodeJson(res)
return json as T
}
// Then in some async function
const myStuff = await fetchStuff<MyDto>('/api/foo')
myStuff.createdAt.getHours() // works
這是有效的,因為響應在轉換為泛型類型之前是any
的,因此 typescript 讓您可以對它做任何事情。 (老實說,我不確定如何使其適應 rxjs 供電代碼)
這種自動轉換日期的整個方法的最大缺點是,如果有人在某個文本字段中手動鍵入日期之類的字符串,它將被轉換為日期,但是您的 Dto 會將其鍵入為字符串,這可能會崩潰你的申請。 例如,有人輸入他們的名字為2015-01-02
。 在我的應用程序中,這是非常不可能的,值得方便。 但這對你來說可能無法忍受。
作為最后的附注,如果 JSON 有一個原生的Date
類型,那么可以避免的頭痛無疑是無數的......
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.