在 typescipt 中,我需要一种方法,让函数在给定特定类型的参数的情况下返回与参数类型相关的类型的对象。
请参阅下面的示例。我需要一种方法来使 'const response = ...' 的类型更窄。
下面的示例用于将特定类型的请求链接到仅与给定请求相关的响应。例如,给定一个查找用户信息的请求,我们想要一个包含他们的姓名和年龄的响应。但是,当收到查找汽车信息的请求时,我们希望得到有关汽车品牌和里程信息的响应。我们只想对“用户”请求使用“用户”响应,对“汽车”使用类似的响应。
class RequestBase {
}
class ResponseBase {
}
interface IFindUserReq {
user_id :string
}
class FindUserRequest implements IFindUserReq {
user_id :string
constructor(user_id) {
this.user_id = user_id
}
}
interface IFindUserRes {
name :string
age :number
}
class FindUserResponse implements IFindUserRes {
name :string
age :number
constructor(name, age) {
this.name = name;
this.age = age;
}
}
interface IFindCarReq {
car_id :number
}
class FindCarRequest implements IFindCarReq {
car_id :number
constructor(car_id) {
this.car_id = car_id
}
}
interface IFindCarRes {
make :string
miles :number
}
class FindCarResponse implements IFindCarRes {
make :string
miles :number
constructor(make, miles) {
this.make = make;
this.miles = miles;
}
}
const request = new FindUserRequest("foo")
const response = performRequest(request) // the type here is 'RequestBase | undefined'. Is there any way to automatically narrow it to be FindCarResponse?
function performRequest(req :RequestBase) : RequestBase | undefined {
if (req instanceof FindUserRequest) {
return new FindUserResponse("foo", 23) // hard coded example for convenience
} else if (req instanceof FindCarRequest) {
return new FindCarResponse("toyota", 10000)
}
}
Run Code Online (Sandbox Code Playgroud)
更新:解决方案 1 受基于字符串文字类型参数的变量返回类型的启发
一种方法是像这样重载“performRequest”签名:
function performRequest(req :FindCarRequest) : FindCarResponse
function performRequest(req :FindUserRequest) : FindUserResponse
function performRequest(req :RequestBase) : ResponseBase | undefined {
if (req instanceof FindUserRequest) {
return new FindUserResponse("foo", 23) // hard coded example for convenience
} else if (req instanceof FindCarRequest) {
return new FindCarResponse("toyota", 10000)
}
}
Run Code Online (Sandbox Code Playgroud)
但是,我真的希望维护请求和响应类型的库不必更改使用请求和响应类型 (performRequest) 的应用程序中的函数签名。所以我还是想听听其他解决方案。
更新解决方案 2 感谢来自 TS Gitter 频道的 Gerrit Birkeland 对此:
class RequestBase {
_responseType : ResponseBase
}
class ResponseBase {
}
interface IFindUserReq {
user_id :string
}
class FindUserRequest extends RequestBase implements IFindUserReq {
_responseType :FindUserResponse
user_id :string
constructor(user_id) {
super()
this.user_id = user_id
}
}
interface IFindUserRes {
name :string
age :number
}
class FindUserResponse extends ResponseBase implements IFindUserRes {
name :string
age :number
constructor(name, age) {
super()
this.name = name;
this.age = age;
}
}
interface IFindCarReq {
car_id :number
}
class FindCarRequest extends RequestBase implements IFindCarReq {
_responseType :FindCarResponse
car_id :number
constructor(car_id) {
super()
this.car_id = car_id
}
}
interface IFindCarRes {
make :string
miles :number
}
class FindCarResponse extends ResponseBase implements IFindCarRes {
make :string
miles :number
constructor(make, miles) {
super()
this.make = make;
this.miles = miles;
}
}
const request = new FindUserRequest("foo")
const response = performRequest<FindUserRequest>(request) // the type of response here is ResponseBase, not sure why it's not narrowed
function performRequest< T extends RequestBase>(req :T) :T["_responseType"] {
if (req instanceof FindUserRequest) {
return new FindUserResponse("foo", 23) // hard coded example for convenience
} else if (req instanceof FindCarRequest) {
return new FindCarResponse("toyota", 10000)
} else {
return new ResponseBase()
}
}
Run Code Online (Sandbox Code Playgroud)
您(大多数)可以通过向类添加属性来实现所需的效果RequestBase。该属性不需要用于任何用途,但它确实需要存在。
(复制自我的 gitter 消息)
class RequestBase {
_responseType: ResponseBase
}
class ResponseBase {}
class FindUserRequest implements RequestBase {
_responseType: FindUserResponse
user_id: string
constructor(user_id: string) {
this.user_id = user_id
}
}
class FindUserResponse {
name: string
age: number
constructor(name: string, age: number) {
this.name = name;
this.age = age;
}
}
const request = new FindUserRequest("foo")
const response = performRequest(request) // FindUserResponse | undefined
function performRequest<T extends RequestBase>(req: T): T["_responseType"] | undefined {
if (req instanceof FindUserRequest) {
return new FindUserResponse("foo", 23)
}
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
822 次 |
| 最近记录: |