Last active
July 11, 2019 09:45
-
-
Save aiya000/59c56cf69effa41f754abded677697c9 to your computer and use it in GitHub Desktop.
Allows to decide take's type
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import * as Untyped from 'tns-core-modules/data/observable' | |
import deprecated from 'deprecated-decorator' // npm install --save-dev deprecated-decorator | |
import { Field, BooleanT, True, False } from '@/data/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<Base extends object, IsDecidable extends BooleanT> extends Untyped.Observable { | |
private constructor() { | |
super() | |
} | |
// TODO: Don't allow this vvv | |
// const x = new Observable<{ value: number }>() | |
// x.assign<'value', number | string>('value', 10 as number | string) | |
/** | |
* A typed safety set() | |
*/ | |
public assign<K extends string, T>(name: Field<Base, 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<Base, K, T>): IsDecidable extends True ? T : (T | undefined) { | |
return super.get(key) | |
} | |
@deprecated('take') | |
public get(name: string): any { | |
super.get(name) | |
} | |
static makeUndecidable<Base extends object>(): Observable<Base, False> { | |
return new Observable<Base, False>() | |
} | |
static makeDecidable<Base extends object>(init: Base): Observable<Base, True> { | |
const x = new Observable<Base, True>() | |
// TODO: 型レベルに計算してあげて(Don't use set()) | |
for (const prop in init) { | |
x.set(prop, init[prop]) | |
} | |
return x | |
} | |
} | |
const x = Observable.makeUndecidable<{value: number}>() | |
const y: number | undefined = x.take('value') | |
// 2322: Type 'number | undefined' is not assignable to type 'number'. Type 'undefined' is not assignable to type 'number'. | |
// const y: number = x.take('value') | |
const a = Observable.makeDecidable<{value: number}>({value: 10}) | |
const b: number = a.take('value') | |
// 2322: Type 'string' is not assignable to type 'number'. | |
// const v = Observable.makeDecidable<{value: number}>({value: 'x'}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Declare a type Value of a property Key via Key of a type Base. | |
* | |
* - 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<Base, Key extends string, Value> = Key extends keyof Base | |
? Value extends Base[Key] ? Key : never | |
: never | |
/** | |
* Maps null to specified fields. | |
* | |
* ```typescript | |
* interface X { | |
* x: number | |
* y: string | |
* z: boolean | |
* } | |
* | |
* type T = Nullable<X, 'x' | 'z'> | |
* // type T = { | |
* // x: number | null | |
* // y: string | |
* // z: boolean | null | |
* // } | |
* ``` | |
*/ | |
export type Nullable<Base, Keys> = { | |
[Key in keyof Base]: Key extends Keys | |
? (Base[Key] | null) | |
: Base[Key] | |
} | |
/** | |
* A type level boolean | |
*/ | |
export interface BooleanT { | |
bool: never | |
} | |
export interface True extends BooleanT { | |
true: never | |
} | |
export interface False extends BooleanT { | |
false: never | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I should use
true
instead ofTrue
, and usefalse
instead ofFalse
.Or I should define
Decidable
andUndecidable
types onto types.ts.