Тип Typescript, основанный на типе входного параметра - PullRequest
0 голосов
/ 29 января 2020

Я пытаюсь сделать что-то следующим образом

const useTeams = (urlFriendlyNameOrId?: string) => {
    const [team, setTeam] = useState<>();
    // Inside of useState<> I want it to evaluate to <Team> if there is a provided string or <Team[]> otherwise
    // I have tried useState<typeof urlFriendlyNameOrId extends string ? Team : Team[]>() will just always give me Team[]
    // I have tried useState<typeof urlFriendlyNameOrId === 'string' ? Team : Team[]() get error about always being false
    ...
    return { team, setTeam };
}

, где он будет генерировать правильную типизацию на основе типа параметра. Я даже дошел до того, что переписал функцию с использованием обобщений, но все еще не могу заставить это работать.

function useTeams<T extends string | undefined>(urlFriendlyNameOrId?: T) {
    const [team, setTeam] = useState<>();
    // useState<T extends string ? Team : Team[]>()
    // useState<typeof T extends string ? Team : Team[]>()
}

1 Ответ

0 голосов
/ 29 января 2020

Я не буду прямо отвечать на вопрос, так как я думаю, что вы пошли не по тому пути. Невозможно использовать условные хуки, это означает, что если ваш хук может работать как с массивом, так и с одним объектом, то это также определение типа.

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

Посмотрите ниже код, я думаю, это то, что вы действительно хотите сделать:

// just example type as you haven't provided such
type Team = {
    name: string;
}

function useTeams(urlFriendlyNameOrId?: string) {
    const [teams, setTeams] = useState<Team | Team[]>(
urlFriendlyNameOrId ? {name: urlFriendlyNameOrId} : []);

    if (Array.isArray(teams)) {
        teams // array
    } else {
        teams // single team
    }
}

Обратите внимание, что ловушка работает с union Team | Team[], я условно передаю начальное значение urlFriendlyNameOrId ? {name: urlFriendlyNameOrId} : [], а также я делаю тип сужение условий после.


Последнее, что у меня получилось, так как я в таких случаях всегда выступаю за меньший ad-ho c полиморфизм, я бы предложил упростить тип до Team[]. Посмотрите, как ваш код изменился бы к лучшему:

function useTeams(urlFriendlyNameOrId?: string) {
    const [teams, setTeams] = useState<Team[]>(
urlFriendlyNameOrId ? [{name: urlFriendlyNameOrId}] : []);

    teams // it can be or empty or one element array of teams
}

Взгляните на мою статью на эту тему - Гибкость функций считается вредной

...