我有一個服務物件,每個都有嵌套請求。我正在嘗試創建一個函式來獲取特定請求,并希望輸出正確的型別。
考慮以下代碼:
enum Service {
Foo = 'foo',
Bar = 'bar'
}
const services = {
[Service.Foo]: {
v1: {
getGreeting: (id: string) => 'hello',
},
},
[Service.Bar]: {
v2: {
getInsult: () => 'idiot',
},
},
};
function createRequest<T extends Service>(
serviceName: T,
version: string,
endpoint: string,
) {
const service = services[serviceName] as typeof services[T];
return service[version][endpoint];
}
const request = createRequest(Service.Foo, 'v1', 'getGreeting');
我快到了,但request有 type any。該函式已經通過泛型知道了服務的型別,但是我如何更加努力地獲取要回傳的嵌套屬性的型別呢?
uj5u.com熱心網友回復:
讓我們為服務資料結構創建一個介面:
type ServiceType = Record<Service, Record<string, Record<string, (...args: any[]) => any>>>;
現在,為了推斷所有引數并驗證它們,我們需要創建這個函式pure。TSpure更喜歡功能。我們應該創建一個回傳另一個函式(curry它)的函式
const withService = <
ServiceObj extends ServiceType
>(services: ServiceObj) =>
<
Name extends keyof ServiceObj,
Version extends keyof ServiceObj[Name],
Endpoint extends keyof ServiceObj[Name][Version]
>(
serviceName: Name,
version: Version,
endpoint: Endpoint,
) => services[serviceName][version][endpoint];
現在我們可以測驗它:
const request = withService({
[Service.Foo]: {
v1: {
getGreeting: (id: string) => 'hello',
},
},
[Service.Bar]: {
v2: {
getInsult: () => 'idiot',
},
},
})
// (id: string) => string
const createRquest = request(Service.Foo, 'v1', 'getGreeting')
// () => string
const createRquest2 = request(Service.Bar, 'v2', 'getInsult')
const createRquest3 = request(Service.Bar, 'v22', 'getInsult') // expected error
操場
您可能已經注意到keyof ServiceObj[Name][Version]反映了函式體邏輯
如果你對函式引數推斷感興趣,可以查看我的相關文章
在這里,您有一個帶有類的版本:
enum Service {
Foo = 'foo',
Bar = 'bar'
}
interface Base {
[prop: `v${number}`]: Record<string, Fn>
}
class Foo {
v1 = {
getGreeting: (id: string) => 2,
}
}
class Bar {
v2 = {
getInsult: () => 'idiot',
}
}
type WithoutIndex = keyof Bar
const services = {
[Service.Foo]: Foo,
[Service.Bar]: Bar,
}
type AnyClass = new (...args: any[]) => Base
type Fn = (...args: any[]) => any
function withService<
ServiceObj extends Record<Service, new (...args: any[]) => any>,
>(services: ServiceObj):
<Name extends Service,
Version extends keyof InstanceType<ServiceObj[Name]>,
Endpoint extends keyof InstanceType<ServiceObj[Name]>[Version]
>(
serviceName: Name,
version: Version,
endpoint: Endpoint,
v?: keyof InstanceType<ServiceObj[Name]>
) => InstanceType<ServiceObj[Name]>[Version][Endpoint]
function withService<
ServiceObj extends Record<Service, AnyClass>,
>(services: ServiceObj) {
return <Name extends Service,
Version extends keyof Base,
Endpoint extends keyof Base[Version]
>(
serviceName: Name,
version: Version,
endpoint: Endpoint,
) => {
const api = new services[serviceName]();
return api[version][endpoint];
}
};
const request = withService({
[Service.Foo]: Foo,
[Service.Bar]: Bar,
})
// (id: string) => number
const createRquest = request(Service.Foo, 'v1', 'getGreeting')
// () => string
const createRquest2 = request(Service.Bar, 'v2', 'getInsult')
const createRquest3 = request(Service.Bar, 'v22', 'getInsult') // expected error
操場
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/409700.html
標籤:
下一篇:打字稿是否允許動態呼叫介面的鍵
