基于输入参数类型的打字稿类型
Typescript Type Based on Input Parameter Type
我正在尝试做如下事情
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[]>()
}
我不会直接回答这个问题,因为我认为你在这里走错了路。不可能使用有条件的钩子,这意味着如果你的钩子可以同时用于数组和单个对象,那也是类型定义。
因为为了缩小类型唯一的方法是设置类型保护,这不能用钩子来完成,所以需要在初始化后设置类型保护。
看看下面的代码,我认为这就是你真正想要做的:
// 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
}
}
注意 hook 与 union Team | Team[]
一起工作,我有条件地传递初始值 urlFriendlyNameOrId ? {name: urlFriendlyNameOrId} : []
,并且我在之后的条件下进行类型缩小。
我的最后一点,因为我在这种情况下总是提倡较少的临时多态性,我建议将类型简化为 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
}
看看我关于这个主题的文章 - Function flexibility considered harmful
我正在尝试做如下事情
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[]>()
}
我不会直接回答这个问题,因为我认为你在这里走错了路。不可能使用有条件的钩子,这意味着如果你的钩子可以同时用于数组和单个对象,那也是类型定义。
因为为了缩小类型唯一的方法是设置类型保护,这不能用钩子来完成,所以需要在初始化后设置类型保护。
看看下面的代码,我认为这就是你真正想要做的:
// 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
}
}
注意 hook 与 union Team | Team[]
一起工作,我有条件地传递初始值 urlFriendlyNameOrId ? {name: urlFriendlyNameOrId} : []
,并且我在之后的条件下进行类型缩小。
我的最后一点,因为我在这种情况下总是提倡较少的临时多态性,我建议将类型简化为 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
}
看看我关于这个主题的文章 - Function flexibility considered harmful