Сопоставленные типы: удалить приватный интерфейс - PullRequest
2 голосов
/ 25 февраля 2020

В TypeScript закрытые атрибуты считаются частью формы (или интерфейса) типа.

class Person {
  constructor(private name: string, public age: number) { }
}
const p: Person = { age: 42 };
// Error: Property 'name' is missing.

Это допустимо, поскольку TypeScript должен отслеживать личные данные.

class Person {
  constructor(private name: string, public age: number) { }
  equals(other: Person) {
    return this.name === other.name && this.age === other.age;
    // This is valid, because TypeScript kept track of the private `name` property!
  }
}

Однако обычно вы хотите игнорировать закрытый интерфейс. Например, когда вы используете внедрение зависимостей и модульное тестирование.

class HttpClient {
   constructor(private log: Logger) {
   }
   async doGet(url: string) { 
      return (await fetch(url)).json();
   }
}

class MyService {
  constructor(private http: HttpClient) {
  }
  // Implementation
}

// Unit test for MyService:
describe('MyService', () => {
  it('should work', () => {
    const httpMock: HttpClient = { // ERROR: Property 'log' is missing
      doGet(url: string) {
         return Promise.resolve({ name: 'Han' });
      }
    };
    const sut = new MyService(httpMock);
  });
});

Я знаю, что мы могли бы решить эту проблему, добавив интерфейс IHttpClient, который описывает интерфейс publi c для HttpClient и используйте это вместо типа класса напрямую, но это большая работа, и ее нужно держать в syn c вручную.

Есть ли способ удалить все неопубликованные свойства c из типа, использующего сопоставленный тип?

Что-то вроде:

type PublicInterface<T> = {
    [P in PublicNames<T>]: T[P];
}

Так что это может быть используется в местах, где вы не заботитесь о рядовых:

class MyService {
  constructor(private http: PublicInterface<HttpClient>) {
  }
  // Implementation
}

1 Ответ

3 голосов
/ 25 февраля 2020

keyof достаточно умен, чтобы смотреть только публичные c клавиши:

class Person {
  constructor(private name: string, public age: number) { }
}

type PublicInterface<T> = {
    [P in keyof T]: T[P];
}

const p: PublicInterface<Person> = { age: 42 }; // no error

Детская площадка


Или даже короче с Утилита Pick (результат эквивалентен указанному выше типу):

type PublicInterface<T> = Pick<T, keyof T>;

Детская площадка

...