A
A
Alex2021-05-20 12:06:16
typescript
Alex, 2021-05-20 12:06:16

How can you restrict an interface to only methods?

I have a system for IPC (Inter Process Communications) in my application. All types of communication are divided into different services. I have described the interfaces for each service, there is a dictionary of all services and a function that, by name, returns a specific service.

Roughly, it looks like this:

// Интерфейс для одного сервиса
interface Service_FOO {
    methodFoo: () => void
}

// Интерфейс для другого сервиса
interface Service_BAR {
    methodBar: () => void
    propertyBar: boolean // <-- Должно привести к ошибке
}


// Словарь всех сервисов и их названий
interface ServiceMap {
    'Service_FOO': Service_FOO
    'Service_BAR': Service_BAR // <-- Или привести к ошибке здесь
}


// Функцыя которая создаёт и возвращает сервис
function createClient<T extends keyof ServiceMap>(name: T) : ServiceMap[T] {
    return {} as ServiceMap[T]
}


// Пользовательский код
const serviceFoo = createClient('Service_FOO')
serviceFoo.methodFoo()


const serviceBar = createClient('Service_BAR')
serviceBar.propertyBar // Приведёт к ошибке в рантайме

Playground

The problem is that, due to implementation peculiarities, createClientall services can only have methods. Hence my question:
How can I restrict the interface itself to contain only methods? Or how to limit the dictionary ServiceMapso that it can contain only interfaces in which only methods?

I tried to do like this:
interface Service_FOO extends Record<string, () => void> {
    methodFoo: () => void
}


interface Service_BAR extends Record<string, () => void>  {
    methodBar: () => void
    
    // @ts-expect-error
    propertyBar: boolean
}


// Class 'FOO' incorrectly implements interface 'Service_FOO'.
// Index signature is missing in type 'FOO'.
class FOO implements Service_FOO {
    methodFoo() {}
}

Playground

And I do get a type error in the interface Service_BAR, but at the same time I started getting an error in the class FOO:
Class 'FOO' incorrectly implements interface 'Service_FOO'.
  Index signature is missing in type 'FOO'.

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Aetae, 2021-05-20
@Kozack

Here you need a little magic:

type ClearIndex<T> = {
  [ P in keyof T as string extends P ? never : P ] : T[P]
};
class FOO implements ClearIndex<Service_FOO > {
    methodFoo() {}
}

The essence of the problem is that it has an "index signature", i.e. declares that accessing any key will return . extends this type (rather than narrows), therefore it has the same index signature and a refined concrete method. The class in ts cannot have an index signature, because is a strict and concrete structure. Record<string, () => void>string() => void
Service_FOOService_FOO

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question