如何避免 TypeScript 中带有 mocha 和未定义 returns 的 if/else?
How can I avoid an if/else in TypeScript with mocha and undefined returns?
一条可以网状的样条和return另一个样条。至少大部分时间。
export default class Spline {
public reticulatedCount: number;
constructor(parent?: Spline) {
this.reticulatedCount = parent && parent.reticulatedCount + 1 || 0;
}
public reticulate(): Spline | undefined {
return new Spline(this);
}
}
import { assert, expect } from 'chai';
import Spline from '../src/spline';
describe("Spline", () => {
const spline = new Spline();
it("returns a new spline", () => {
const reticulatedSpline = spline.reticulate();
expect(reticulatedSpline).to.not.be.null;
expect(reticulatedSpline.reticulatedCount).to.eq(1);
});
});
失败 error TS2532: Object is possibly 'undefined'.
/Users/dblock/source/ts/typescript-mocha/node_modules/ts-node/src/index.ts:245
return new TSError(diagnosticText, diagnosticCodes)
^
TSError: ⨯ Unable to compile TypeScript:
test/spline.spec.ts:18:12 - error TS2532: Object is possibly 'undefined'.
18 expect(reticulatedSpline.reticulatedCount).to.eq(1);
解决方法是测试中的反模式,if
。
it("returns a new spline", () => {
const reticulatedSpline = spline.reticulate();
if (reticulatedSpline) {
expect(reticulatedSpline.reticulatedCount).to.eq(1);
} else {
expect(reticulatedSpline).to.not.be.null;
}
});
如何在不禁用 strictNullChecks
的情况下解决这个问题?
https://github.com/dblock/typescript-mocha-strict-null-checks 中的代码。
您可以使用 non-null
(!
) 运算符。
it("always can be reticulated again", () => {
const reticulatedSpline = spline.reticulate();
expect(reticulatedSpline).to.not.be.null;
expect(reticulatedSpline!.reticulatedCount).to.eq(1);
});
如文档所述:
[You] may be used to assert that its operand is non-null and non-undefined in contexts where the type checker is unable to conclude that fact
因为 .to.not.be.null
不影响这些示例中的代码流,TS 目前无法推断它对传递给它的参数进行了更改。有一个 code-flow 依赖的方法可以使用 user-defined type guards.
function assertNotNull<T>(v: T | null): v is NonNullable<T> {
if (!v) throw new Error();
return true
}
declare const maybeAString: string | undefined
function ex() {
// Doesn't work because TS has no way to know that this will throw
assertNotNull(maybeAString)
maybeAString
// Control flow analysis knows that this function will validate that maybeAString is definitely not null
if(assertNotNull(maybeAString)) {
maybeAString // now definitely a string
}
// control flow analysis knows that the branch where maybeAString isn't not null (aka is null) returns, so the main path must be non-null
if(!assertNotNull(maybeAString)) return
maybeAString // now definitely a string
}
更新了引入“断言签名”的 Typescript 3.7 示例:
/**
* Use in place of `expect(value).to.exist`
*
* Work-around for Chai assertions not being recognized by TypeScript's control flow analysis.
* @param {any} value
*/
export function expectToExist<T>(value: T): asserts value is NonNullable<T> {
expect(value).to.exist;
if (value === null || value === undefined) {
throw new Error('Expected value to exist');
}
}
参考文献:
一条可以网状的样条和return另一个样条。至少大部分时间。
export default class Spline {
public reticulatedCount: number;
constructor(parent?: Spline) {
this.reticulatedCount = parent && parent.reticulatedCount + 1 || 0;
}
public reticulate(): Spline | undefined {
return new Spline(this);
}
}
import { assert, expect } from 'chai';
import Spline from '../src/spline';
describe("Spline", () => {
const spline = new Spline();
it("returns a new spline", () => {
const reticulatedSpline = spline.reticulate();
expect(reticulatedSpline).to.not.be.null;
expect(reticulatedSpline.reticulatedCount).to.eq(1);
});
});
失败 error TS2532: Object is possibly 'undefined'.
/Users/dblock/source/ts/typescript-mocha/node_modules/ts-node/src/index.ts:245
return new TSError(diagnosticText, diagnosticCodes)
^
TSError: ⨯ Unable to compile TypeScript:
test/spline.spec.ts:18:12 - error TS2532: Object is possibly 'undefined'.
18 expect(reticulatedSpline.reticulatedCount).to.eq(1);
解决方法是测试中的反模式,if
。
it("returns a new spline", () => {
const reticulatedSpline = spline.reticulate();
if (reticulatedSpline) {
expect(reticulatedSpline.reticulatedCount).to.eq(1);
} else {
expect(reticulatedSpline).to.not.be.null;
}
});
如何在不禁用 strictNullChecks
的情况下解决这个问题?
https://github.com/dblock/typescript-mocha-strict-null-checks 中的代码。
您可以使用 non-null
(!
) 运算符。
it("always can be reticulated again", () => {
const reticulatedSpline = spline.reticulate();
expect(reticulatedSpline).to.not.be.null;
expect(reticulatedSpline!.reticulatedCount).to.eq(1);
});
如文档所述:
[You] may be used to assert that its operand is non-null and non-undefined in contexts where the type checker is unable to conclude that fact
因为 .to.not.be.null
不影响这些示例中的代码流,TS 目前无法推断它对传递给它的参数进行了更改。有一个 code-flow 依赖的方法可以使用 user-defined type guards.
function assertNotNull<T>(v: T | null): v is NonNullable<T> {
if (!v) throw new Error();
return true
}
declare const maybeAString: string | undefined
function ex() {
// Doesn't work because TS has no way to know that this will throw
assertNotNull(maybeAString)
maybeAString
// Control flow analysis knows that this function will validate that maybeAString is definitely not null
if(assertNotNull(maybeAString)) {
maybeAString // now definitely a string
}
// control flow analysis knows that the branch where maybeAString isn't not null (aka is null) returns, so the main path must be non-null
if(!assertNotNull(maybeAString)) return
maybeAString // now definitely a string
}
更新了引入“断言签名”的 Typescript 3.7 示例:
/**
* Use in place of `expect(value).to.exist`
*
* Work-around for Chai assertions not being recognized by TypeScript's control flow analysis.
* @param {any} value
*/
export function expectToExist<T>(value: T): asserts value is NonNullable<T> {
expect(value).to.exist;
if (value === null || value === undefined) {
throw new Error('Expected value to exist');
}
}
参考文献: