In TypeScript, private attributes are considered part of the shape (or interface) of a type.
class Person {
constructor(private name: string, public age: number) { }
}
const p: Person = { age: 42 };
// Error: Property 'name' is missing.
This is valid, because TypeScript needs to keep track of privates.
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!
}
}
However, there usually you want to ignore the private interface. For example, when you're using dependency injection and unit testing.
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);
});
});
I know we could solve this by adding an interface IHttpClient which describes the public interface for an HttpClient and use that instead of the class type directly, but that is a lot of work and it need to be kept in sync manually.
Is there a way to remove all non-public properties from a type using a mapped type?
Something like:
type PublicInterface<T> = {
[P in PublicNames<T>]: T[P];
}
So it could be used in places where you do not care about privates:
class MyService {
constructor(private http: PublicInterface<HttpClient>) {
}
// Implementation
}
keyof is smart enough to peek only public keys:
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
Playground
Or even shorter with Pick utility (the result is equivalent to above mapped type):
type PublicInterface<T> = Pick<T, keyof T>;
Playground
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With