如何避免Typescript中的可选链接?

jv4diomz  于 2023-01-02  发布在  TypeScript
关注(0)|答案(2)|浏览(128)

我尝试在redux中存储名为Targetfarms的对象数据,我将名为Farmstype的类型赋给了Targetfarms
但是,当我将TargetfarmsuseSelector一起带入MainPage组件中,并且我希望使用targetfarm.aircon时,如果我不在Targetfarms中使用可选链接,则会发生此错误。

Targetfarms is possibly null,

如果我使用可选链接,我可以正常地获得Targetfarms数据,但我不想尽可能多地使用可选链接。
如何修复我的代码?
这是我的代码:

export interface Farmstype {
    aircon: aircontype;
    children: Farmstype[];
    equips: euiptype[];
    latitude: number;
    longitude: number;
    modDate: string;
    name: string;
    placeId: number;
    placeInfo: placeInfotype;
    productCode: string;
    productCodeInfo: productCodeInfotypes;
    productLifeCycles: productLifeCyclestype[];
    roadNameAddress: string;
    stnIds: number;
    type: string;
}

interface InitialState {
    Targetfarms: Farmstype | null;
}

const initialState: InitialState = {
    Targetfarms: null,
};


const postSlice = createSlice({
    name: "post",
    initialState,
    reducers: {
        // targetLoadFarm
        targetFarm(state, action: PayloadAction<Farmstype>) {
            state.Targetfarms = action.payload;
        },
    }

主页

const MainPage = () => {
    const { Targetfarms} = useSelector((state: RootState) => state.post);

    console.log("Targetfarms:", Targetfarms?.placeId);    // Targetfarms is possibly null,

}
tp5buhyn

tp5buhyn1#

也许你正在访问一个对象的属性,而这个属性在初始化之前可能是空的或未定义的。为了避免这个错误,你有几个选择:
在尝试访问对象的属性之前,可以检查对象是否为空或未定义。例如:

if (Targetfarms) {
  console.log(Targetfarms.placeId);
}

您可以使用设置Targetfarms的默认值||运算符。例如:

const {Targetfarms} = useSelector((state: RootState) => state.post) || {};
console.log(Targetfarms.placeId);

这会将Targetfarms的默认值设置为空对象,这意味着您可以访问其属性而不会收到错误。
注意:我认为,这只是我的意见,可选链接是一个很好的方法,以避免空或未定义。

lokaqttq

lokaqttq2#

摆脱当前设置中的可选链接的一个想法是静态地输入世界的状态并编写不同的组件。
我不确定我是否正确地构建了你的商店,但你明白我的意思。

type RootState = {
    app: 'init' | 'running' // we model the state of the app
    post: {
       Targetfarms: Farmstype | null
    }
}

// We dispatch to the correct implementation depending on the state of the world
const MainPage = () =>
    useSelector({ app }: RootState) => app) === 'running'
        ? RunningPage()
        : InitPage();

const RunningPage = () => {
    const { Targetfarms } = useSelector((state: RunningState) => state.post);

    // OK
    const f = Targetfarms.placeId

}

const InitPage = () => {
    const { Targetfarms } = useSelector((state: InitState) => state.post);

    // @ts-expect-error: Targetfarms is possibly null
    const f = Targetfarms.placeId

}

有很多方法可以产生不同的状态,这是一个选项。

// When the app is 'running' `post/Targetfarms` is unlocked
type RunningState = Unlock<RootState, ['post', 'Targetfarms']> & {
   state: 'running'
};

// Otherwise Targetfarms is still nullable
type InitState = RootState & {
   state: 'init'
};

type Unlock<State, Path extends PropertyKey[]> = unknown & {
    [K in keyof State]: Path['length'] extends 1
        ? K extends Path[0] ? NonNullable<State[K]> : State[K]
        : Unlock<
            State[K],
            Path extends [PropertyKey, ...infer U] ? U  & PropertyKey[] : never
        >
}

如果app状态很少,而状态的可空片段很多,那么这个解决方案就开始变得有趣了。基本上,您只需在根目录下一次决定应用处于什么状态,而不是在需要值的地方多次决定。

相关问题