programing

유형 스크립트 어설션과 같은 유형 가드

yellowcard 2023. 7. 19. 21:17
반응형

유형 스크립트 어설션과 같은 유형 가드

다음을 제외하고 유형을 제한할 수 있습니까?if함수 호출에 의해never예를 들어 반환undefined맘에 들다assert유형 스크립트에서?

코드 예제:

interface Foo { bar(): void }
function getFoo(): Foo | undefined { }

function test() {
    const foo = someService.getFoo();
    assert(foo);
    if (!foo) { // now mandatory because without this foo may be still undefined even if assert protects us from this
        return;
    }
    foo.bar(); // , here foo may be undefined
}

나는 글을 쓸 수 있기를 원합니다.assert내가 따라가지 않을 수 있는 방법으로.if (!foo)절과 을 가지다.foo평문으로 제한된 활자Foo.

Typescript에서 이것이 가능합니까?

오버로드를 추가해 보았습니다.never다음을 던지는 유형:

function assertGuard(v: undefined | null | '' | 0 | false): never;
function assertGuard(v: any): void; // i'm not sure which one is  captured by TS typesystem here

function assertGuard<T>(v: T | undefined) {
    if (v === undefined || v === null || v === '' || v === 0 || v === false) {
         throw new AssertionError({message: 'foo'})
    }
}

이것은 컴파일하지만 호출합니다.assertGuard(foo)에 대해 그것을 인식하지 못합니다.undefined돌아올 것입니다.never그래서 제한하지 않습니다.foo로.Foo.

가능한 해결책을 찾았지만 고전적이라고 생각합니다.assert보다 깔끔한 접근 방식:

function assertResultDefined<T>(v: T|undefined): T | never {
    if (v === undefined) {
        throw new Error('foo');
    }
    return v;
}
function die(): never { throw new Error('value expected)}

const foo = assertResultDefined(getFoo()) // foo is Foo, undefined is erased
const foo = getFoo() || die();
    // undefined is erased from foo
    / CONS: doesn't play well with types that interpolate to `false` like 0, ''

유형 스크립트 3.7은 제어 흐름 분석에 주장을 추가합니다.

asserts반환 형식 술어는 어설션이 유지될 때만 함수가 반환되고 그렇지 않을 때는 예외를 반환함을 나타냅니다.

소비자 측의 해킹은 더 이상 필요하지 않습니다.

interface Foo { bar(): void }
declare function getFoo(): Foo | undefined;

function assert(value: unknown): asserts value {
    if (value === undefined) {
        throw new Error('value must be defined');
    }
}

function test() {
    const foo = getFoo();
    // foo is Foo | undefined here
    assert(foo);
    // foo narrowed to Foo
    foo.bar();
}

놀이터.


또한 제공된 매개 변수가 필수 유형이라고 주장할 수 있습니다.

declare function assertIsArrayOfStrings(obj: unknown): asserts obj is string[];

function foo(x: unknown) {
    assertIsArrayOfStrings(x);
    return x[0].length;  // x has type string[] here
}

놀이터.

https://github.com/Microsoft/TypeScript/issues/8655 에 대한 유형 스크립트 백로그에 문제가 있습니다.그래서 지금은 이것을 할 수 없습니다.

당신이 할 수 있는 것은 어설션 연산자 "!"를 사용하는 것입니다.! 뒤에 값을 추가하면 값이 정의되지 않았거나 null이 아닙니다.null 또는 정의되지 않은 참조로 이어질 수 없다고 확신하는 경우 사용합니다.

function test() {
     const foo: (FooType|null) = getFoo();
     foo!.bar(); // "!" - asserts that foo is not null nor undefined
}

출처: https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-type-assertions

부터foo이라Foo | undefined그것의 유형은 로 변경되어야 합니다.Foo어떻게든.

위의 코드에서 이 작업은 다음을 통해 수행할 수 있습니다.

let foo = getFoo(); // Foo | undefined
foo = assertResultDefined(foo); // Foo
foo.bar();

또 다른 옵션은 null이 아닌 어설션을 사용하는 것입니다(다른 답변에서 알 수 있듯이).

let foo = getFoo();
foo = assertResultDefined(foo);
foo = foo!;
foo.bar();

이것은 당신에게 효과가 있을 것입니다.

const foo = (a: number | null) => {
  a = shouldBe(_.isNumber, a)
  a  // TADA! a: number
}

const shouldBe = <T>(fn: (t1) => t1 is T, t) => (fn(t) ? t : throwError(fn, t))

const throwError = (fn:Function, t) => {
  throw new Error(`not valid, ${fn.name} failed on ${t}`)
}

어디에_.isNumber타입 가드가 있습니다.x is number이것은 타입 가드와 함께 어떤 기능에도 사용할 수 있습니다.

핵심은 변수를 재할당해야 하기 때문에 효과적으로assert실패한 유형 어설션에 오류를 발생시키는 ID 함수입니다.

형식 안전성이 있는 원라이너:

function assert<T>(value: T | undefined): T {
  if (value === undefined) {
    throw new Error('value is undefined');
  }

  return value;
}

언급URL : https://stackoverflow.com/questions/49362725/typescript-assert-like-type-guard

반응형