Skip to content

Instantly share code, notes, and snippets.

@aiya000
Last active July 8, 2019 05:15

Revisions

  1. aiya000 revised this gist Jul 8, 2019. 2 changed files with 15 additions and 16 deletions.
    21 changes: 5 additions & 16 deletions Observable.ts
    Original file line number Diff line number Diff line change
    @@ -1,23 +1,12 @@
    import * as Untyped from 'tns-core-modules/data/observable'
    import deprecated from 'deprecated-decorator' // npm install --save-dev deprecated-decorator

    /**
    * ValueTypes<{foo: number, bar: string}> = number | string
    */
    type ValueTypes<T> = T extends { [k: string]: infer I }
    ? I
    : never

    /**
    * Field<'foo', {foo: number, bar: string}> = 'foo'
    */
    type Field<X, K extends string, T> = K extends keyof X
    ? X[K] extends T ? K : never
    : never
    import { Field } from '@/data/conditional-types'

    /**
    * Don't dirty your hands.
    * You must use this instead of [[Untyped.Observable]].
    *
    * This description is [here](http://aiya000.github.io/posts/2019-07-04-recover-nativescript-type-unsafe-observable.html).
    */
    export default class Observable<X extends object> extends Untyped.Observable {
    constructor() {
    @@ -39,8 +28,8 @@ export default class Observable<X extends object> extends Untyped.Observable {
    /**
    * A type safety get()
    */
    public take<K extends string, T>(key: Field<X, K, T>): T {
    return super.get(key)
    public take<K extends string, T>(key: Field<X, K, T>): T | null {
    return super.get(key) || null
    }

    @deprecated('take')
    10 changes: 10 additions & 0 deletions conditional-types.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,10 @@
    /**
    * Declare a type T of a property K via K of a type X.
    *
    * - Field<{foo: number, bar: string}, 'foo', number> = 'foo'
    * - Field<{foo: number, bar: string}, 'bar', string> = 'bar'
    * - Field<{foo: number, bar: string}, 'foo', string> = never
    */
    export type Field<X, K extends string, T> = K extends keyof X
    ? T extends X[K] ? K : never
    : never
  2. aiya000 revised this gist Jul 5, 2019. 2 changed files with 29 additions and 10 deletions.
    23 changes: 16 additions & 7 deletions Observable.ts
    Original file line number Diff line number Diff line change
    @@ -11,31 +11,40 @@ type ValueTypes<T> = T extends { [k: string]: infer I }
    /**
    * Field<'foo', {foo: number, bar: string}> = 'foo'
    */
    type Field<K extends string, T> = K extends keyof T
    ? K
    type Field<X, K extends string, T> = K extends keyof X
    ? X[K] extends T ? K : never
    : never

    /**
    * Don't dirty your hands.
    * You must use this instead of [[Untyped.Observable]].
    *
    * Unfortunately, still this is a little type unsafe.
    * Please see the comment of [https://github.com/aiya000/workspace/blob/7cc4c5e53a74036e9c2339cc39d6ee0f47f8a315/TypeScript/ConditionalTypes/type-untyped-method.ts].
    */
    export default class Observable<T extends object> extends Untyped.Observable {
    export default class Observable<X extends object> extends Untyped.Observable {
    constructor() {
    super()
    }

    /**
    * A typed safety set()
    */
    public assign<K extends string>(name: Field<K, T>, value: ValueTypes<T>): void {
    public assign<K extends string, T>(name: Field<X, K, T>, value: T): void {
    super.set(name, value)
    }

    @deprecated('assign')
    public set(name: string, value: any): void {
    super.set(name, value)
    }

    /**
    * A type safety get()
    */
    public take<K extends string, T>(key: Field<X, K, T>): T {
    return super.get(key)
    }

    @deprecated('take')
    public get(name: string): any {
    super.get(name)
    }
    }
    16 changes: 13 additions & 3 deletions using.ts
    Original file line number Diff line number Diff line change
    @@ -1,3 +1,13 @@
    const x: Observable<{value?: number}> = new Observable<{value?: number}>()
    x.assign('value', 10)
    // x.assign('value', 'a') // 2345: Argument of type '"a"' is not assignable to parameter of type 'number | undefined'.
    const p = new Observable<{ x: number, y: string }>()
    p.assign('x', 10)
    p.assign('y', 'poi')
    // 2345: Argument of type '"y"' is not assignable to parameter of type 'never'.
    // p.assign('y', 10)

    const x: number = p.take('x')
    const y: string = p.take('y')

    // 2345: Argument of type '"y"' is not assignable to parameter of type 'never'.
    // const e: number = p.take('y')

    // Use {x?: number, y?: string} if you are careful to forget initializing :D
  3. aiya000 revised this gist Jul 4, 2019. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions using.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,3 @@
    const x: Observable<{value?: number}> = new Observable<{value?: number}>()
    x.assign('value', 10)
    // x.assign('value', 'a') // 2345: Argument of type '"a"' is not assignable to parameter of type 'number | undefined'.
  4. aiya000 revised this gist Jul 4, 2019. 1 changed file with 3 additions and 0 deletions.
    3 changes: 3 additions & 0 deletions Observable.ts
    Original file line number Diff line number Diff line change
    @@ -18,6 +18,9 @@ type Field<K extends string, T> = K extends keyof T
    /**
    * Don't dirty your hands.
    * You must use this instead of [[Untyped.Observable]].
    *
    * Unfortunately, still this is a little type unsafe.
    * Please see the comment of [https://github.com/aiya000/workspace/blob/7cc4c5e53a74036e9c2339cc39d6ee0f47f8a315/TypeScript/ConditionalTypes/type-untyped-method.ts].
    */
    export default class Observable<T extends object> extends Untyped.Observable {
    constructor() {
  5. aiya000 created this gist Jul 4, 2019.
    38 changes: 38 additions & 0 deletions Observable.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,38 @@
    import * as Untyped from 'tns-core-modules/data/observable'
    import deprecated from 'deprecated-decorator' // npm install --save-dev deprecated-decorator

    /**
    * ValueTypes<{foo: number, bar: string}> = number | string
    */
    type ValueTypes<T> = T extends { [k: string]: infer I }
    ? I
    : never

    /**
    * Field<'foo', {foo: number, bar: string}> = 'foo'
    */
    type Field<K extends string, T> = K extends keyof T
    ? K
    : never

    /**
    * Don't dirty your hands.
    * You must use this instead of [[Untyped.Observable]].
    */
    export default class Observable<T extends object> extends Untyped.Observable {
    constructor() {
    super()
    }

    /**
    * A typed safety set()
    */
    public assign<K extends string>(name: Field<K, T>, value: ValueTypes<T>): void {
    super.set(name, value)
    }

    @deprecated('assign')
    public set(name: string, value: any): void {
    super.set(name, value)
    }
    }