英文:
How to conditionally change the type in typescript in angular?
问题
I am making an angular component dependent on the API Response.
我正在创建一个Angular组件,其依赖于API响应。
I am getting these from an API Response.
我从API响应中获取这些信息。
-
When there's no error
-
当没有错误时
Data : {
Status: string;
Data: number;
} -
When there's an Error I am getting this.
-
当出现错误时,我会得到以下内容。
Data : {
Status: string;
Error: string;
Message: string;
}
As we can see Status is common I tried implementing this.
正如我们所看到的,状态(Status)是共同的,我尝试实现了这一点。
interface ApiModel {
Status: string;
}
interface DataModel extends ApiModel {
Data: number;
}
interface ErrorModel extends ApiModel {
ErrorCode: string;
Message: string;
}
I am trying to use the typescript to give it my variable an option where it can be either one and then pass that type in its response too.
我试图使用TypeScript为我的变量提供一个选项,它可以是其中之一,然后将该类型传递给其响应。
I don't want to use optional type here hence I am facing these issues.
我不想在这里使用可选类型,因此我面临了这些问题。
What I am expecting is,
我期望的是,
if (typeof Response === DataModel){
if (Response instanceof DataModel) {
Response: DataModel;
// Other code
}
else {
Response: ErrorModel;
// Other code
}
The API call here
这里的API调用
getReminder(reminderId: number) {
const API_URL = ${this.BASE_URL}users/${this.userId}/reminders/${reminderId}
;
return this.httpClient.get<ErrorModel | DataModel>(API_URL, this.options).pipe(
map((data: ErrorModel | DataModel) => {
return data;
})
);
}
英文:
I am making an angular component dependent on the API Response.
I am getting these from an API Response.
-
When there's no error
Data : {
Status: string;
Data: number;
} -
When there's an Error I am getting this.
Data : {
Status: string;
Error: string;
Message: string;
}
As we can see Status is common I tried implementing this.
interface ApiModel {
Status: string;
}
interface DataModel extends ApiModel {
Data: number;
}
interface ErrorModel extends ApiModel {
ErrorCode: string;
Message: string;
}
I am trying to use the typescript to give it my variable an option where it can be either one and then pass that type in it's response too.
I don't want to use optional type here hence I am facing these issues.
What I am expecting is,
if (typeof Response === DataModel){
Response: DataModel;
// Other code
}
else {
Response:ErrorModel;
// Other code
}
The API call here
getReminder(reminderId: number) {
const API_URL = `${this.BASE_URL}users/${this.userId}/reminders/${reminderId}`;
return this.httpClient.get<ErrorModel | DataModel>(API_URL, this.options).pipe(
map((data: ErrorModel | DataModel) => {
return data;
})
);
}
答案1
得分: 2
根据你的请求,以下是代码的翻译:
接口 DataModel {
状态: 'success';
数据: number;
}
接口 ErrorModel {
状态: 'error';
错误码: string;
消息: string;
}
类型 ApiModel = DataModel | ErrorModel;
函数 foo(响应数据: ApiModel): void {
如果 (响应数据.状态 === 'success') {
控制台.记录(响应数据.数据);
} 否则 {
控制台.记录(响应数据.错误码);
}
}
foo({状态: 'success', 数据: 10});
接口 ApiModelBase {
状态: string;
}
接口 DataModel 扩展自 ApiModelBase {
数据: number;
}
接口 ErrorModel 扩展自 ApiModelBase {
错误码: string;
消息: string;
}
类型 ApiModel = DataModel | ErrorModel;
函数 isDataModel(响应: ApiModel): 响应 是 DataModel {
返回 (响应 as DataModel).数据 !== undefined;
}
函数 foo(响应数据: ApiModel): void {
如果 (isDataModel(响应数据)) {
控制台.记录(响应数据.数据);
} 否则 {
控制台.记录(响应数据.错误码);
}
}
foo({状态: 's1', 数据: 10});
请注意,我已经将代码中的注释和链接保留在原文中。
英文:
To my eyes your model looks like Discriminated union
If you model it correctly, the compiler will be able to do the narrowing without extra code.
Note that:
- there is no need to downcast after the type predicate check
- discriminator checks one of two union members - if it is not DataModel, the compiler can deduce that it is an ErrorModel
interface DataModel {
Status: 'success';
Data: number;
}
interface ErrorModel {
Status: 'error'
ErrorCode: string;
Message: string;
}
type ApiModel = DataModel | ErrorModel;
function foo(responseData: ApiModel): void {
if (responseData.Status === 'success') {
console.log(responseData.Data);
} else {
console.log(responseData.ErrorCode);
}
}
foo({Status: 'success', Data: 10});
If you cannot model your data as a discriminated union, you still model the response as a union, but you will have to resort to a [Type predicate] to verify which member of the union you are dealing with
interface ApiModelBase {
Status: string;
}
interface DataModel extends ApiModelBase {
Data: number;
}
interface ErrorModel extends ApiModelBase {
ErrorCode: string;
Message: string;
}
type ApiModel = DataModel | ErrorModel;
function isDataModel(response: ApiModel): response is DataModel {
return (response as DataModel).Data !== undefined;
}
function foo(responseData: ApiModel): void {
if (isDataModel(responseData)) {
console.log(responseData.Data);
} else {
console.log(responseData.ErrorCode);
}
}
foo({Status: 's1', Data: 10});
答案2
得分: 0
可以使用这个模式来测试接收到的类型,进行内联类型转换:
function isDataModel(response: ApiModel): response is DataModel {
return (response as DataModel).Data !== undefined;
}
// 当`responseData`是从API收到的实际响应时
const responseData: ApiModel = ...;
if (isDataModel(responseData)) {
// 响应是DataModel类型
const dataResponse: DataModel = responseData;
// DataModel的其他代码
} else {
// 响应是ErrorModel类型
const errorResponse: ErrorModel = responseData;
// ErrorModel的其他代码
}
英文:
You could use this pattern to test what type you are receiving with some inline type conversion:
function isDataModel(response: ApiModel): response is DataModel {
return (response as DataModel).Data !== undefined;
}
// when `responseData` is the actual response received from the API
const responseData: ApiModel = ...;
if (isDataModel(responseData)) {
// The response is of type DataModel
const dataResponse: DataModel = responseData;
// Other code for DataModel
} else {
// The response is of type ErrorModel
const errorResponse: ErrorModel = responseData;
// Other code for ErrorModel
}
答案3
得分: 0
你尝试过在 TypeScript 中使用联合类型来实现你想要的吗?
type YourResponse = DataModel | ErrorModel;
以下是可能的示例用法:
const response: YourResponse = {
Status: "Success",
Data: 100,
};
if (response instanceof DataModel) {
这是一个 DataModel。
} else if (response instanceof ErrorModel) {
这是一个 ErrorModel。
}
英文:
Did you try using Union type in TypeScript to achieve what you want?
type YourResponse = DataModel | ErrorModel;
This could be the example usage:
const response: YourResponse = {
Status: "Success",
Data: 100,
};
if (response instanceof DataModel) {
It is a DataModel.
} else if (response instanceof ErrorModel) {
It is an ErrorModel.
}
答案4
得分: -1
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
isDataModel(response: ApiModel): response is DataModel {
return response.Status === 'success';
}
getReminder(reminderId: number): Observable<DataModel | ErrorModel> {
const API_URL = `${this.BASE_URL}users/${this.userId}/reminders/${reminderId}`;
return this.httpClient.get<ApiModel>(API_URL, this.options).pipe(
map((response: ApiModel) => {
if (isDataModel(response)) {
const responseData: DataModel = response as DataModel;
return responseData;
} else {
// ErrorModel handling
const errorResponse: ErrorModel = response as ErrorModel;
throw errorResponse;
}
})
);
}
interface ApiModel {
Status: string;
}
interface DataModel extends ApiModel {
Data: number;
}
interface ErrorModel extends ApiModel {
ErrorCode: string;
Message: string;
}
英文:
import { HttpClient, HttpErrorResponse } from '@angular/common/http';
import { Observable } from 'rxjs';
import { map } from 'rxjs/operators';
isDataModel(response: ApiModel): response is DataModel {
return response.Status === 'success';
}
getReminder(reminderId: number): Observable<DataModel | ErrorModel> {
const API_URL = `${this.BASE_URL}users/${this.userId}/reminders/${reminderId}`;
return this.httpClient.get<ApiModel>(API_URL, this.options).pipe(
map((response: ApiModel) => {
if (isDataModel(response)) {
const responseData: DataModel = response as DataModel;
return responseData;
} else {
// ErrorModel handling
const errorResponse: ErrorModel = response as ErrorModel;
throw errorResponse;
}
})
);
}
Interfaces can be as earlier
interface ApiModel {
Status: string;
}
interface DataModel extends ApiModel {
Data: number;
}
interface ErrorModel extends ApiModel {
ErrorCode: string;
Message: string;
}
Let me know if there are any issues or clarifications needed.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论