Interfaz dada una interfaz:

class A {
   method(x:number) : string
}

Función dada

const b = (x: string) : number;

El objetivo: probar la función frente a la interfaz

Realización

type InterfaceKey = {
    method: any
};

function typecheck<T, K extends keyof InterfaceKey >(imp: () => T, d: T[K]) {
 //                                   K cannot be used to index type T ^
    imp();
    return d;
}

typecheck(someclass, 555); // <-- type check _is actually works_ here

// or

function typecheck <T>(imp: () => T, d: any) {
    imp();
    if(!d) {
        let mock: T;
        mock.default = d; // default does not exists on type T 
        return mock;
    }
    return d;
}

Parece que el primer enfoque es la única forma, e incluso realiza una verificación de tipo (en Webstorm, no en tsc), pero no se compila.

Relacionado: https://github.com/Microsoft/TypeScript/issues/15768

0
Anton Korzunov 15 nov. 2017 a las 02:32

2 respuestas

La mejor respuesta
//base interface
interface MyInterface {
    method: any 
}

// check with defined method
interface CheckD<T extends MyInterface> {
    all(keys: {[P in keyof T]?: T[P]}): Check<T>;

    onlyMethod<Ts extends {[K in keyof Ts]: Ts[K]} & T>(fn: Ts['method']): Check<T>;
}

// check without
interface Check<T> {
    all(keys: {[P in keyof T]?: T[P]}): Check<T>;
}

type CCD<T extends MyInterface > = CheckD<T>;
type CC<T> = Check<T>;

// magic
function uncast(a: any): any{
    return <any>a;
}

// function overloading
function load<K extends MyInterface>(a: K): CCD<K>;
function load<T>(a: T): CC<T>;

// type guards
function load<T, K extends MyInterface>(a: T|K): CCD<K> | CC<T>{
    if ((<K>a).method) return <CCD<K>>uncast(a);
    return <CC<T>> uncast(a);
}

// TEST

var C1 = {
    test: a => a + 1,
    method: a => 5
}

var C2 = {
    test: a => a + 1,    
}

let a1 = load(C1);
a1.all({ test: a => 1 });
a1.onlyMethod(55); // type error

let a2 = load(C2);
a2.all({ test: (a,b) => 1 }); // type error
a2.all({ test2: a => 1 });// type error
a2.onlyMethod(55); //no such method

Entonces, en realidad, el resultado es bastante comprensible.

0
Anton Korzunov 15 nov. 2017 a las 05:17

¿Va esto en la dirección correcta?

class someclass {
  method(x: number): string { return null!; };
}

const b = (x: number): string => null!;

type InterfaceKey = {
  method: any
};

function typecheck<T extends InterfaceKey>() {
  return <K extends keyof InterfaceKey>(d: T[K]) => {};
}

// should fail if signature of someclass's `method` doesn't match that of `b`
typecheck<someclass>()(b);
0
dbandstra 15 nov. 2017 a las 01:09