-
Notifications
You must be signed in to change notification settings - Fork 1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
StoreName type check not depends on infer #10
Conversation
これストア名を間違えた場合に型エラーになる? 手元ではならないけれど。。。?? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
難しい && 悩ましい
name: string; | ||
defaultValue: T; | ||
storeName: StoreName | string; | ||
// Avoid inference to rigorously check type arguments | ||
storeName: StoreName extends infer S ? S : never; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
これがうまくいくにはStoreName
のデフォルトがQiitaの記事のようにnever
でないとダメなのでは?
string extends infer S
だとS
はstring
をキャプチャしてしまうからnever
にはならないと思われ
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LocationStateDefinition
単体ではこれで推論されることはなくなる+明示的に型引数で指定するとうまくいってました。
Qiitaの記事は型引数を必ず指定することを目的として推論させない+neverデフォルトなアプローチであって、推論されることを防ぐのみならStoreName extends infer S ? S : never;
でOKだからうまくいったんだと思ってました。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LocationStateDefinition
単体だとstoreName: StoreName
でもエラーになっていたはず
つまり型変数StoreName
が普通にDefaultStoreName(s)
になるんでしょう
関数の型推論が特別に強力なんだろうなぁ
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
あ、確かにでした。
関数の推論をStoreName extends infer S ? S : never;
で防げるからうまくいくってところですかね...?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
この修正もう不要ですよね?
storeName: StoreName
でいいはず
const counter: LocationStateDefinition<number> = {
name: "count",
defaultValue: 0,
storeName: "session",
}; これを書き換えてエラーになって安心してました。 |
デフォルト引数指定足したらうまく行きました。 // ✅
const counter: LocationStateDefinition<number> = {
name: "count",
defaultValue: 0,
storeName: "session",
};
// ✅
const counter: LocationStateDefinition<number, "other"> = {
name: "count",
defaultValue: 0,
storeName: "other",
};
// ❌
const counter: LocationStateDefinition<number> = {
name: "count",
defaultValue: 0,
storeName: "other",
};
// ❌
const counter: LocationStateDefinition<number, "other"> = {
name: "count",
defaultValue: 0,
storeName: "session",
};
// ✅
const [count, setCount] = useLocationState({
name: "count",
defaultValue: 0,
storeName: "session",
});
// ✅
const [count, setCount] = useLocationState<number, 'other'>({
name: "count",
defaultValue: 0,
storeName: "other",
});
// ❌
const [count, setCount] = useLocationState({
name: "count",
defaultValue: 0,
storeName: "other",
});
// ❌
const [count, setCount] = useLocationState<number, 'other'>({
name: "count",
defaultValue: 0,
storeName: "session",
}); |
GJ!!! |
そうしたかったんですが逆にすると↓のエラーになってしまって、他にやりよう思いつかずな状況です...
|
ちょっと発想を変えてみる export type LocationStateDefinition<StoreNames extends string, T> = {...};
const _useLocationState = <StoreNames extends string, T>(
definition: LocationStateDefinition<StoreNames, T>,
): [T, SetState<T>] => {
const storeState = _useLocationStateValue(definition);
const setStoreState = _useLocationSetState(definition);
return [storeState, setStoreState];
};
const _useLocationStateValue = <StoreNames extends string, T>(
definition: LocationStateDefinition<StoreNames, T>,
): T => {
...
};
const _useLocationSetState = <StoreNames extends string, T>(
definition: LocationStateDefinition<StoreNames, T>,
): SetState<T> => {
...
};
export const withStoreNames = <StoreNames extends string>() =>
({
useLocationState: _useLocationState,
useLocationStateValue: _useLocationStateValue,
useLocationSetState: _useLocationSetState,
} as {
useLocationState: <T>(
definition: LocationStateDefinition<StoreNames, T>,
) => [T, SetState<T>];
useLocationStateValue: <T>(
definition: LocationStateDefinition<StoreNames, T>,
) => T;
useLocationSetState: <T>(
definition: LocationStateDefinition<StoreNames, T>,
) => SetState<T>;
});
export const { useLocationState, useLocationStateValue, useLocationSetState } =
withStoreNames<DefaultStoreNames>(); 独自のストア名を使う場合は const { useLocationState } = withStoreNames<"foo" | "bar">()
export const Component = () => {
const [count, setCount] = useLocationState({
...
storeName: "foo",
});
}; 通常はプロジェクトの一カ所で |
なるほどです!
|
してます、最後の↓がそれです export const { useLocationState, useLocationStateValue, useLocationSetState } =
withStoreNames<DefaultStoreNames>();
上に書いたデフォルトストア版と重複定義になっちゃうんですよね
いいですよ type MyStoreNames = "foo" | "bar";
const {...} = getHooksWith<MyStoreNames>(); というのもアリかもしれない
これに対してはあまりポジティブではない、、、けどやってくれて構いません |
上に貼ったコードのgenerics、 |
なるほどです |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ちょっとコメントしてますが修正してもらったらマージOKです!乙でした!
name: string; | ||
defaultValue: T; | ||
storeName: StoreName | string; | ||
// Avoid inference to rigorously check type arguments | ||
storeName: StoreName extends infer S ? S : never; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
この修正もう不要ですよね?
storeName: StoreName
でいいはず
@@ -25,16 +29,19 @@ const useStore = (storeName: StoreName | string) => { | |||
return store; | |||
}; | |||
|
|||
export const useLocationState = <T>( | |||
definition: LocationStateDefinition<T>, | |||
const _useLocationState = <T, StoreName extends string = DefaultStoreNames>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
型引数のデフォルトも不要かなと
definition: LocationStateDefinition<T>, | ||
const _useLocationStateValue = < | ||
T, | ||
StoreName extends string = DefaultStoreNames, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
同上
@@ -56,8 +63,8 @@ export const useLocationStateValue = <T>( | |||
return storeState; | |||
}; | |||
|
|||
export const useLocationSetState = <T>( | |||
definition: LocationStateDefinition<T>, | |||
const _useLocationSetState = <T, StoreName extends string = DefaultStoreNames>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
同上
@@ -78,3 +85,23 @@ export const useLocationSetState = <T>( | |||
); | |||
return setStoreState; | |||
}; | |||
|
|||
export const getHooksWith = <StoreNames extends string>() => |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
自分のせいだけどStoreNames
とStoreName
で一貫性がなくなってますね。。。
DefaultStoreNames
も含めてどちらかに揃えたい
元々はデフォルトのストア (2つあるから複数) の名前なので複数形がいいかなと思ってDefaultStoreNames
にしてもらったんだけど、このファイルの型引数の場合は単独のストア名の型だから単数形にするべきですよねぇ
そうするとDefaultStoreNames
も単数形にすべきか。。。
なんかそんな気がしてきたので単数形に揃えますか
手間を増やして申し訳ない
@@ -1,6 +1,6 @@ | |||
/// <reference types="navigation-api-types" /> | |||
|
|||
export type StoreName = "session" | "url"; | |||
export type DefaultStoreNames = "session" | "url"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ということでDefaultStoreName
で
# Conflicts: # packages/location-state-core/package.json # packages/location-state-next/package.json
↑も修正しました! |
誤った
storeName
指定時にtypecheckでfailするよう修正。