我有一个这样的Typescript类:
export class Contract {
constructor (
public id: string,
public name: string,
public spend: number
) {}
}
这是由使用如下中间类的服务加载的:
export class ContractService {
// the stuff you would expect
public loadContracts() {
this.httpService.get(this.contractEndpoint).subscribe((result) => this.createContracts(result));
}
private createContracts(contracts: Array<Contract>) {
for ( let contract of contracts ) {
console.log("Contract spend is "+contract.spend+": "+( typeof contract.spend));
}
}
}
当我运行它时,在我的控制台中我看到:
Contract spend is 10000: string
Contract spend is 1222: string
Contract spend is 20001: string
但是,如果我尝试使用parseInt(contract.spend)
,那么Typescript编译器就会拒绝,因为它知道contract.spend是一个数字,所以在编译时它知道应该是什么值。
我假设我的rest服务中的JSON将spend
字段作为引号返回,但它似乎正在以一种默默失败的方式破坏Typescript的核心优势之一。我需要做什么来确保我的数字字段包含一个数字,或者当错误的类型传递给它时,我的代码会失败?
发布于 2019-08-02 09:48:45
TypeScript在编译时工作,但它会编译为JavaScript。因此,在运行时,只剩下很好的旧JS。
这意味着:如果您的服务在TypeScript未知的情况下为contract.spend
提供字符串值,TypeScript将无法知晓。
如果您希望在这种情况下利用静态类型,请让TypeScript知道您的HTTP调用的响应体具有哪种类型。然后主动地将响应从响应正文类型转换为您期望的类型。
例如:
type HttpContractResponse = {
spend: string
}[];
export class ContractService {
// the stuff you would expect
constructor(private httpService: HttpService,
private contractEndpoint = 'http://endpoint.com') {}
public loadContracts() {
this.httpService.get<HttpContractResponse>(this.contractEndpoint)
.subscribe((result) => this.createContracts(result));
}
private createContracts(rawContracts: HttpContractResponse) {
const contracts: Contract[] = rawContracts.map(rc => {return {
...rc,
spend: +rc.spend
}});
for (let contract of contracts) {
console.log('Contract spend is ' + contract.spend + ': ' + (typeof contract.spend));
}
}
}
发布于 2019-08-09 09:24:44
我建议你看看typescript-json-validator
,它将提供类型安全验证,确认一些未知的json匹配你的typescript接口(你应该为JSON数据定义接口而不是类,它不能包含方法,所以一个接口就足以描述它)。
文件app/interfaces/contract.ts
export interface IContract {
id: string;
name: string;
spend: number;
}
运行此命令(在安装模块之后),它将生成一个新文件contract.validator.js
yarn typescript-json-validator --collection --aliasRefs --noExtraProps --strictNullChecks --coerceTypes app/interfaces/contract.ts
下面是一个使用示例:
import {validate} from "./interfaces/contract.validator";
const validateContract = validate('IContract');
const data: unknown = JSON.parse('{ "id": "42", "name": "Joe", "spend": "10000"}');
const contract = validateContract(data);
console.log(`Contract spend is ${contract.spend}: ${typeof contract.spend}` );
输出为:
Contract spend is 10000: number
contract
的类型在这里是IContract
,并且所有类型都将匹配。你不必告诉typescript const contract: IContract
,因为它会正确地推断出类型,但如果你愿意的话,你可以这样做。
如果JSON没有包含正确的字段,或者它们没有预期的类型,它将抛出一个错误。命令中的--coerceTypes
选项允许进行一些转换,例如将字符串转换为数字。您还可以在界面的注释中包含其他约束,如正则表达式模式,请参阅文档。如果将多个接口放在一个文件中,--collection
选项可以确保它们都可用,只需创建一个单独的验证器,传递每个接口的名称即可。
有一些恼人的限制,所以在界面中只使用简单的字符串和数字。例如,不要使用Date作为类型,因为它会验证字段是一个包含ISO格式日期的字符串,但它不会强制该类型,因此您仍然会得到一个字符串。但是,您可以使用注释来说明它是一个具有正确日期或日期-时间格式的字符串,然后使用经过验证的接口中的正确字段构造一个类。
发布于 2019-08-02 09:43:58
TypeScript类型在编译过程中会被移除--因为JavaScript ( TypeScript被转译为它)没有静态类型的概念。因此,在运行时“开箱即用”期间,无法确保值的类型正确。
https://stackoverflow.com/questions/57323811
复制相似问题