Skip to content

User-defined type assertions #17760

Closed
Closed
@maghis

Description

@maghis

Proposal: support user-defined type assertions (keyword as) in addition to user-defined type guards (keyword is).

A user-defined type assertion is a function with a return type expressed as in the following example (continuing the handbook example in "Advanced Types").

function assertIsFish(pet: Fish | Bird): pet as Fish {
    if (!isFish(pet))
        throw new Error("birds are not supported");
}

assertIsFish(pet);

pet.swim();

:pet as fish means that, if the function assertIsFish returns without throwing, pet is automatically asserted to be of type Fish.

Use-cases:

  1. Validators: user-defined type assertions make it possible to encapsulate in functions the type narrowing that is currently available through control flow analysis. They also allow types that better describe the behavior of many existing libraries, including: node asserts, data validators that throw detailed errors, many test frameworks.

  2. Polyfills: enables describing functions that modify objects by adding new properties.

addName<T>(obj: T): obj as T & { name: string } {
    obj.name = "Mike";
}

const obj = {};
addName(obj);

obj.name.indexOf("i");

Validator examples:

simple undefined checking

function notUndefined<T>(obj: T | undefined): obj as T {
    if (obj === undefined)
        throw new Error("invalid object");
}

const myObj: string | undefined = {} as any;

// [ts] Object is possibly 'undefined'.
myObj.indexOf("");

notUndefined(myObj);

// no errors
myObj.indexOf("");

joi-like validation currently requires implementing the schema description of an object for runtime checking and copying the schema to an interface to have static type checking while the static type could be inferred by the implementation of the schema

interface Schema<T> {
    validate(obj: any): obj is T;
}

function attemptValidation<T>(obj: any, schema: Schema<T>): obj as T {
    if (!schema.validate(obj))
        throw new Error("very detailed object validation error");
}

// complex schema implements T and T is inferred by the schema construction
// this is already possible
const complexSchema = Joi.object({
    myField: Joi.date().iso()
});

attemptValidation(objFromTheRealWorld, complexSchema);

const day = objFromTheReadWorld.myField.getDay();

Metadata

Metadata

Assignees

No one assigned

    Labels

    FixedA PR has been merged for this issueSuggestionAn idea for TypeScript

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions