Typescript 如何根据条件返回属性类型?

Typescript 如何根据条件返回属性类型?,typescript,typescript2.0,Typescript,Typescript2.0,在我的项目中,我有- 我也可以这样设置- myServiceSpy.doSomething.and.returnValue('someVal'); 但是我遗漏了两件事: 1.忽略getter和setter函数的能力 就类型而言,我想忽略getter和setter,因为通过设置属性可以很容易地模拟它们 目前,如果我试图设置一个具有如下setter函数的属性,TypeScript会抱怨 MyService{ set url(value:string){ this._url

在我的项目中,我有-

我也可以这样设置-

myServiceSpy.doSomething.and.returnValue('someVal');
但是我遗漏了两件事: 1.忽略getter和setter函数的能力 就类型而言,我想忽略getter和setter,因为通过设置属性可以很容易地模拟它们

目前,如果我试图设置一个具有如下setter函数的属性,TypeScript会抱怨

MyService{
    set url(value:string){
        this._url = value;
    }
}

let myServiceSpy: Spy<MyService> = createSpyFromClass(MyService);
我得到这个错误-

Type '"test"' is not assignable to type 'string & AsyncSpyFunction'.
所以我希望能够忽略类型定义本身中的setter和getter

2.根据原始返回类型返回不同的间谍类型 我希望能够在原始函数返回可观测值时返回可观测值

承诺和其他异步类型也是如此

每种方法都有自己独特的方法

目前我只使用一个catch-all类型,它有所有可能实现的间谍方法,但我更喜欢更具体一些

那么让我们假设我有以下课程-

class MyService{
    getUsers():Observable<User[]> {
        return Observable.of(users);
    }

    getToken():Promise<Token> {
        return Promise.resolve(token);
    }
}
我希望方法
nextWith
仅对返回可观察值的方法显示

并且,
resovleWith
仅对返回承诺的方法显示


是否可以以某种方式进行配置?

在typescript 2.8的发行版中,您可以使用映射的条件类型进行配置:

import { Observable } from "rxjs";

export type Spy<T> = { [k in keyof T]: AddSpyTypes<T[k]> };

export type AddSpyTypes<T> = T extends (...args: any[]) => any
  ? AddSpyByReturnTypes<T>
  : T;

export interface PromiseSpy<T> {
  resolveWith(value: T): void;
  rejectWith(value: any): void;
}

export interface ObservableSpy<T> {
  nextWith(value: T): void;
  nextWithError(value: any): void;
}

export type AddSpyOnFunction<T extends (...args: any[]) => R, R> = T & {
  and: jasmine.Spy;
};

export type AddSpyOnPromise<T extends Promise<any>> = T & {
  and: PromiseSpy<Unpacked<T>>;
};
export type AddSpyOnObservable<T extends Observable<any>> = T & {
  and: ObservableSpy<Unpacked<T>>;
};

// Wrap the return type of the given function type with the appropriate spy methods
export type AddSpyByReturnTypes<
  TF extends (...args: any[]) => any
> = TF extends (...args: any[]) => infer TR // returnes a function
  ? TR extends (...args: any[]) => infer R2
    ? AddSpyOnFunction<TR, R2> // returnes a Promise
    : TR extends Promise<any>
      ? AddSpyOnPromise<TR> // returnes an Observable
      : TR extends Observable<any> ? AddSpyOnObservable<TR> : TF
  : never;

//github.com/Microsoft/TypeScript/issues/21705#issue-294964744
export type Unpacked<T> = T extends (infer U)[]
  ? U
  : T extends (...args: any[]) => infer U
    ? U
    : T extends Promise<infer U> ? U : T extends Observable<infer U> ? U : T;
从“rxjs”导入{Observable};
导出类型Spy={[k in keyof T]:AddSpyTypes};
导出类型AddSpyTypes=T扩展(…args:any[])=>any
? AddSpyByReturnTypes
:T;
导出接口PromiseSpy{
resolveWith(值:T):无效;
rejectWith(值:任意):无效;
}
可观察的导出接口{
nextWith(值:T):无效;
nextWithError(值:任意):无效;
}
导出类型addSpyonR,R>=T&{
还有:茉莉花,间谍;
};
导出类型AddSpyOnPromise
myServiceSpy.url = 'test';
Type '"test"' is not assignable to type 'string & AsyncSpyFunction'.
class MyService{
    getUsers():Observable<User[]> {
        return Observable.of(users);
    }

    getToken():Promise<Token> {
        return Promise.resolve(token);
    }
}
myServiceSpy.getUsers.and.nextWith(fakeUsers);
myServiceSpy.getToken.and.resolveWith(fakeToken);
import { Observable } from "rxjs";

export type Spy<T> = { [k in keyof T]: AddSpyTypes<T[k]> };

export type AddSpyTypes<T> = T extends (...args: any[]) => any
  ? AddSpyByReturnTypes<T>
  : T;

export interface PromiseSpy<T> {
  resolveWith(value: T): void;
  rejectWith(value: any): void;
}

export interface ObservableSpy<T> {
  nextWith(value: T): void;
  nextWithError(value: any): void;
}

export type AddSpyOnFunction<T extends (...args: any[]) => R, R> = T & {
  and: jasmine.Spy;
};

export type AddSpyOnPromise<T extends Promise<any>> = T & {
  and: PromiseSpy<Unpacked<T>>;
};
export type AddSpyOnObservable<T extends Observable<any>> = T & {
  and: ObservableSpy<Unpacked<T>>;
};

// Wrap the return type of the given function type with the appropriate spy methods
export type AddSpyByReturnTypes<
  TF extends (...args: any[]) => any
> = TF extends (...args: any[]) => infer TR // returnes a function
  ? TR extends (...args: any[]) => infer R2
    ? AddSpyOnFunction<TR, R2> // returnes a Promise
    : TR extends Promise<any>
      ? AddSpyOnPromise<TR> // returnes an Observable
      : TR extends Observable<any> ? AddSpyOnObservable<TR> : TF
  : never;

//github.com/Microsoft/TypeScript/issues/21705#issue-294964744
export type Unpacked<T> = T extends (infer U)[]
  ? U
  : T extends (...args: any[]) => infer U
    ? U
    : T extends Promise<infer U> ? U : T extends Observable<infer U> ? U : T;
    // p is interface with the the promise props, PO is an interface with the observer props 
export type Spy<T, P, PO> = T & {
  [k in keyof P]: AsyncSpyFunctionAnd<P[k]>;
} & {
  [k in keyof PO]: AsyncSpyFunctionAndObserver<PO[k]>;
}

export interface AsyncSpyFunction<T> extends jasmine.Spy {
  (...params: any[]): any;
  and: AsyncSpyFunctionAnd<T>;
}

export interface AsyncSpyFunctionAnd<T> extends jasmine.SpyAnd {
  resolveWith(value: T): void;
  rejectWith(value: any): void;
}

export interface AsyncSpyFunctionAndObserver<T> extends jasmine.SpyAnd {
  nextWith(value: T): void;
  nextWithError(value: any): void;
}