@nakonechnikistryi

Как назначить интерфейс с обязательными полями для контекста без дефолтного значения?

Есть контекст в отдельном файле context.ts:

import React from 'react';
import SomeClass from '.....';

interface IContext {
  someClass: SomeClass;
}

// я должен назначить контексту интерфейс, чтобы видеть в других местах приложения его конкретные свойства
const Context= React.createContext<IContext>({});

export default Context;


И здесь будет ошибка, потому что я в дефолтное значение конктекста не прокинул экземпляр SomeClass. И в свою очередь внутри файла с контекстом я этот экземпляр класса создать не могу, поскольку этот класс требует в конструкторе определенный параметр, к которому нет доступа. Все создается в каком-то другом месте:

const someValue = 'someValue';

<Context.Provider value={{ someClass: new SomeClass(someValue ) }}>
  {children}
</Context.Provider>


Как тогда назначить интерфейс контексту? Чтобы избавиться от ошибки, я могу разве что обернуть IContext в Partial, чтобы сделать поля необязательными, но это так себе решение:

const Context= React.createContext<Partial<IContext >>({});
  • Вопрос задан
  • 61 просмотр
Решения вопроса 1
Alexandroppolus
@Alexandroppolus
кодир
На мою имху, лучше всего такой вариант:
const Context= React.createContext(null as unknown as IContext);

...
const { someClass } = useContext(Context);


да, это обман тайпскрипта и ошибка переедет в рантайм, но в случае с контекстом такого не избежать, потому как TS не может проконтролировать наличие провайдера. Данный вариант сразу обнаруживает ошибку в рантайме во время дебага, после чего следует одноразовая починка - добавляется забытый провайдер.

если компонент, использующий значение из контекста, может без него обойтись, и например, что-то осмысленное нарисовать, то можно так:
const Context= React.createContext<IContext | null>(null);


тогда useContext вернет IContext | null, то есть значение просто надо проверять на null и в этом случае что-то делать - например, отрендерить какое-то сообщение. Но если от значения контекста зависят другие хуки, то везде надо втыкать проверку и будет лишний говнокод.

худший вариант - воткнуть в createContext бессмысленную заглушку, формально соответствующую интерфейсу. Это так же приведет к ошибке в рантайме (если забыли провайдер), но ошибка будет скорее всего малопонятная, в отличии от первого варианта.

ну и разумеется, в контексте может лежать что-то простое, например, текущий язык, тогда задание дефолтного значения имеет смысл.
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
@wonderingpeanut
interface MyLittleInterface {
  age: number;
  name: string;
}

const someVar: MyLittleInterface = {}; // ой-ой! 
const someOtherVar: MyLittleInterface = {} as MyLittleInterface; // Ура!
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы