Typescript: Support explicit type compatibility assertion

Created on 18 Jun 2017  路  8Comments  路  Source: microsoft/TypeScript

Sometimes we may want to explicitly assert whether the type of a expression is compatible with a certain type, but type assertion does not satisfy the type safety we want:

interface SomeEventData {
  foo: number;
  bar: string;
}

this.emit('some-event', {foo: 123} as SomeEventData);

The behavior is desired but it would be nice if we have an elegant way for more secure type checking instead of:

let data: SomeEventData = {foo: 123};

E.g.:

this.emit('some-event', {foo: 123}: SomeEventData);
Needs Proposal Suggestion

Most helpful comment

I cannot find other discussion on this, but I have also thought it would be useful to have a type-assertion like operator that doesn't actually coerce the type of the expression.

This operator:

  1. Still provides a contextual type.
  2. Can be used on any expression.
  3. Has the type of the contained expression (rather than the type being ensured/checked against).

For example:

interface Foo {
    bar(x: string): void;
}

// 'x' has type
//
//    {
//        bar(a: string): void,
//        baz(): number
//    }
//
const x = {
    bar(a) {
      console.log(a.toLowerCase());
    }
    baz() {
      return 100;
    }
} compatibleWith Foo;

All 8 comments

Even better: make sure that incompatible types will raise a type error

class MyEvent<A> {
  readonly _A: A
  constructor(readonly name: string) {}
}

type Handler<A> = (a: A) => void

declare class MyEventEmitter {
  on<A>(event: MyEvent<A>): (handler: Handler<A>) => void
  emit<A>(event: MyEvent<A>): (a: A) => void
}

interface SomeEventData {
  foo: number
  bar: string
}

const emitter = new MyEventEmitter()
const someEvent = new MyEvent<SomeEventData>('some-event')

emitter.emit(someEvent)({}) // error
emitter.emit(someEvent)({ foo: 'a' }) // error
emitter.emit(someEvent)({ foo: 1, bar: 's' }) // ok

emitter.on(someEvent)(() => {}) // ok
emitter.on(someEvent)((foo: number) => {}) // error
emitter.on(someEvent)(foo => {}) // ok
emitter.on(someEvent)((foo: SomeEventData) => {}) // ok

@gcanti Looks nice (sharing data type between emit and on)! Though creating a wrapper that persists at runtime does not sound ideal to me, especially when we have a lot of libs adapting to implementations like EventEmitter.

Yeah, maybe a branded type instead of a class?

type MyEvent<A> = string & { _A: A } // branded type, the runtime representation is still a string

function createEvent<A>(name: string): MyEvent<A> {
  return name as any
}

const someEvent = createEvent<SomeEventData>('some-event')

I cannot find other discussion on this, but I have also thought it would be useful to have a type-assertion like operator that doesn't actually coerce the type of the expression.

This operator:

  1. Still provides a contextual type.
  2. Can be used on any expression.
  3. Has the type of the contained expression (rather than the type being ensured/checked against).

For example:

interface Foo {
    bar(x: string): void;
}

// 'x' has type
//
//    {
//        bar(a: string): void,
//        baz(): number
//    }
//
const x = {
    bar(a) {
      console.log(a.toLowerCase());
    }
    baz() {
      return 100;
    }
} compatibleWith Foo;

@gcanti Nice try, but it would still be weird working with existing event emitters. :(

migrated from #20188

in my code i often use, let's call them, type invariants assertions:

function mustBe<T>(_: () => T): void {}
interface A {
    isThat: true;
    text: string;
}
interface B {
    isThat: false;
    value: number;
}
type C = A | B;
declare const C: C;
mustBe<true>(() => C.isThat); // <-- type error as expected

now i wish i could do type invariant assertions without emitting any useless code, making it a zero cost abstraction:

makesure C.isThat sameas true;

where makesure is a new TS syntax/construct that participates in type checking, but doesn't get emitted

few more examples

makesure typeof c.isThat subtypeof boolean
makesure MyClass subtypeof BaseClass
// ...

c.f. #7481

Tracking at #7481 / #26064

Was this page helpful?
0 / 5 - 0 ratings

Related issues

zhuravlikjb picture zhuravlikjb  路  3Comments

weswigham picture weswigham  路  3Comments

jbondc picture jbondc  路  3Comments

dlaberge picture dlaberge  路  3Comments

siddjain picture siddjain  路  3Comments