简体   繁体   English

'{ [key: string]: any; 类型的参数 }' 不可分配给“any[]”类型的参数

[英]Argument of type '{ [key: string]: any; }' is not assignable to parameter of type 'any[]'

I am trying to do a simple pokemon application using ngrx.我正在尝试使用ngrx 做一个简单的口袋妖怪应用程序。 I am using lodash library to do a key value array.我正在使用 lodash 库来做一个键值数组。 I have had success in almost all steps i need to fill my MatTableDataSource, but i thing i am not knowing how to give the correct type to this.我在填充 MatTableDataSource 所需的几乎所有步骤中都取得了成功,但我不知道如何为此提供正确的类型。 So i need to receive my data and fill my dataSource.data with that but i receive this error : "Argument of type '{ [key: string]: any; }' is not assignable to parameter of type 'any[]'. Type '{ [key: string]: any; }' is missing the following properties from type 'any[]': length, pop, push, concat, and 26 more".所以我需要接收我的数据并用它填充我的dataSource.data,但我收到此错误:“类型'{ [key:string]:any;}'的参数不可分配给'any []'类型的参数。类型 '{ [key: string]: any; }' 缺少类型 'any[]' 中的以下属性:length、pop、push、concat 和另外 26 个”。 Because this, my table is not rendered.因为这个,我的表没有渲染。 How to give the correct type to my MatTableDataSource or fix this issue?如何为我的 MatTableDataSource 提供正确的类型或解决此问题?

Regards问候

My Observable that hear the reponse and set the value to the MatTableDataSource 'pokemon.component.ts'我的 Observable 听到响应并将值设置为 MatTableDataSource 'pokemon.component.ts'

public readonly pokemonsSubscription = this.store.pipe(select(fromPokemons.pokemons)).subscribe(pokemons => {
    if (!pokemons || pokemons.length === 0) {
      return;
    }
    //the error is below
    this.dataSource.data = new MatTableDataSource(pokemons);

    this.dataSource.paginator = this.paginator;
    this.dataSource.sort = this.sort;
  });

This is my pokemon storage 'pokemon.store.ts'这是我的口袋妖怪存储'pokemon.store.ts'

export const selectPokemonsState = (appState: AppState) => appState.Pokemons;

export const pokemons = createSelector(selectPokemonsState, (pokemonsState: PokemonsState) => pokemonsState.pokemons);
export const isLoading = createSelector(selectPokemonsState, (pokemonsState: PokemonsState) => pokemonsState.isLoading);
export const initial = createSelector(selectPokemonsState, (pokemonsState: PokemonsState) => pokemonsState.initial);
export const final = createSelector(selectPokemonsState, (pokemonsState: PokemonsState) => pokemonsState.final);

These are my actions 'pokemons.actions.ts'这些是我的动作'pokemons.actions.ts'

export enum Action {
    PokemonsLoad = '[Pokemons] Load',
    PokemonsLoadSuccess = '[Pokemons] Load Success',
    PokemonsLoadError = '[Pokemons] Load Error',
    PokemonLoadByQuantity = '[Pokemon] Load By Quantity',
    PokemonLoadByQuantitySuccess = '[Pokemon] Load By Quantity Success',
    PokemonLoadByQuantityError = '[Pokemon] Load By Quantity Error',
}

export const PokemonsLoad = createAction(Action.PokemonsLoad);
export const PokemonsLoadSuccess = createAction(Action.PokemonsLoadSuccess, props<{ payload: Array<any> }>());
export const PokemonsLoadError = createAction(Action.PokemonsLoadError, props<{ payload: any }>());
export const PokemonLoadByQuantity = createAction(Action.PokemonLoadByQuantity, props<{ payload: { initial: number, final: number }}>());
export const PokemonLoadByQuantitySuccess = createAction(Action.PokemonLoadByQuantitySuccess, props<{ payload: Array<any> }>());
export const PokemonLoadByQuantityError = createAction(Action.PokemonsLoadError, props<{ payload: any }>());

My reducer 'pokemons.reducer.ts'我的减速器'pokemons.reducer.ts'

export interface PokemonsState {
    pokemons: { [key: string]: any };
    isLoading: boolean;
    initial: number;
    final: number;
    quantityOfAllPokemons: number;
}

export const pokemonsInitialState: PokemonsState = {
    pokemons: {},
    isLoading: false,
    initial: 1,
    final: 24,
    quantityOfAllPokemons: undefined,
};

const pokemonsReducer = createReducer(
    pokemonsInitialState,
    on(pokemonsActions.PokemonsLoadSuccess, (state, { payload }) => (
        {
            ...state,
            pokemons: keyBy(PokemonNumber.pokemonNumber(payload), 'id'),
            isLoading: false,
            quantityOfAllPokemons: payload.length
        }
    )
    ),
    on(pokemonsActions.PokemonLoadByQuantitySuccess, (state, { payload }) => (
        {
            ...state,
            pokemons: keyBy( Object.values(state.pokemons).concat(payload), 'id'),
            isLoading: false,
            initial: PokemonNumber.nextSearch(state.final, state.quantityOfAllPokemons, 1),
            final: PokemonNumber.nextSearch(state.final, state.quantityOfAllPokemons, 12)
        }
    )
    ),
    on(pokemonsActions.PokemonsLoad, (state) => (
        {
            ...state,
            isLoading: true
        }
    )
    ),
    on(pokemonsActions.PokemonLoadByQuantity, (state) => (
        {
            ...state,
            isLoading: true
        }
    )
    ),
);

export function reducer(pokemonState: PokemonsState | undefined, action: Action) {
    return pokemonsReducer(pokemonState, action);
}

export const pokemonsFeatureKey = 'Pokemons';

The effects 'pokemons.effects.ts'效果'pokemons.effects.ts'

@Injectable()
export class PokemonsEffects {

    loadAllPokemons$ = createEffect(() => this.actions$.pipe(
        ofType(Action.PokemonsLoad),
        switchMap((payload) => {
            return this.pokemonsService.getAllPokemons()
                .pipe(
                    map(pokemons => (PokemonsLoadSuccess({ payload: pokemons }))),
                    catchError((msg) => of(PokemonsLoadError({ payload: msg }))),
                );
        })
    )
    );

    loadPokemonByQuantity$ = createEffect(() => this.actions$.pipe(
        ofType(Action.PokemonLoadByQuantity),
        switchMap((payload) => {
            return this.pokemonsService.loadPokemonByQuantity(payload['payload']['initial'], payload['payload']['final'])
                .pipe(
                    map(pokemons => (PokemonLoadByQuantitySuccess({ payload: pokemons }))),
                    catchError((msg) => of(PokemonLoadByQuantityError({ payload: msg }))),
                );
        })
    )
    );

    success$ = createEffect(() => this.actions$.pipe(
        ofType<{ type: string, payload: any }>(
            // Action.PokemonsLoadSuccess,
            // Action.PokemonLoadByQuantitySuccess,
        ),
        tap(({ type, payload }) => { window.alert('Sucesso'); })
    ), { dispatch: false });

    error$ = createEffect(() => this.actions$.pipe(
        ofType<{ type: string, payload: string }>(
            Action.PokemonsLoadError,
            Action.PokemonLoadByQuantityError,
        ),
        tap(({ type, payload }) => { window.alert('Erro'); }),
    ), { dispatch: false });

    constructor(private actions$: Actions, private pokemonsService: PokemonsService) { }
}

My stackblitz about this error is below我关于这个错误的 stackblitz 如下

stackblitz堆栈闪电战

The error indicates that you are trying to assign an object to a property of type array.该错误表明您正在尝试将对象分配给数组类型的属性。 In the line below:在下面的行中:

this.dataSource.data = new MatTableDataSource(pokemons);

MatTableDataSource() expects an array, but seems like pockemons is not a proper array of objects. MatTableDataSource()需要一个数组,但似乎pockemons不是一个正确的对象数组。 You can verify this for example by doing console.log(Array.isArray(pockemons));例如,您可以通过执行console.log(Array.isArray(pockemons));来验证这一点。 . .

Once you confirm that pockemons is an not an array of objects, you can work on making that object into the array of objects (or post a separate question).一旦您确认pockemons不是对象数组,您就可以将该对象放入对象数组中(或发布单独的问题)。

You should also change the line above to this (drop .data ):您还应该将上面的行更改为此(删除.data ):

this.dataSource = new MatTableDataSource(pokemons);

Update更新

Upon closer inspection of your stackblitz, it seems like when pokemons is retrieved from the store, even though it's a series of objects, it is not coming in as an array of objects.在仔细检查您的 stackblitz 后,似乎从商店中检索pokemons时,即使它是一系列对象,它也不是作为对象数组进入的。

I am using lodash library to do a key value array我正在使用 lodash 库来做一个键值数组

You are not creating an array at all, it's actually an object of objects, sample:您根本没有创建数组,它实际上是对象的对象,示例:

{
    "1": {
        "name": "bulbasaur",
        "url": "https://pokeapi.co/api/v2/pokemon/1/",
        "id": 1
    },
    "2": {
        "name": "ivysaur",
        "url": "https://pokeapi.co/api/v2/pokemon/2/",
        "id": 2
    }
}

I don't see why you would actually need to do this, and according to how your table is set up, it expects an array like you get from the API.我不明白为什么您实际上需要这样做,并且根据您的表的设置方式,它需要一个像您从 API 获得的数组。 Anyway you are using pokemonNumber to create the id for your pokemons, which you are using to fetch the individual data for each pokemon in PokemonLoadByQuantitySuccess .无论如何,您正在使用pokemonNumber为您的 pokemon 创建 id,您使用它来获取PokemonLoadByQuantitySuccess中每个 pokemon 的单独数据。

So I would do:所以我会这样做:

on(pokemonsActions.PokemonsLoadSuccess, (state, { payload }) => (
  {
    ...state,
    pokemons: PokemonNumber.pokemonNumber(payload), // <<<<<<<<<< this instead
    // pokemons: keyBy(PokemonNumber.pokemonNumber(payload), 'id'),
    isLoading: false,
    quantityOfAllPokemons: payload.length
  }
)

Okay, then when fetching data for each pokemon, you are using concat , which is not suitable here, since you are then just concatenating the arrays.好的,那么在为每个 pokemon 获取数据时,您正在使用concat ,这在这里不适合,因为您只是连接数组。 What you want is to attach data to the specific pokemon based on the id.您想要的是根据 id 将数据附加到特定的口袋妖怪。 This might be done cleaner, but at least this works:这可能会做得更干净,但至少这是可行的:

on(pokemonsActions.PokemonLoadByQuantitySuccess, (state, { payload }) => (
  {
    ...state,
    // pokemons: keyBy( Object.values(state.pokemons).concat(payload), 'id'),
    // below instead!!
    pokemons: state.pokemons.map((p, i) => { return {... p, ...payload.find(i => i.id === p.id)}}),
    isLoading: false,
    initial: PokemonNumber.nextSearch(state.final, state.quantityOfAllPokemons, 1),
    final: PokemonNumber.nextSearch(state.final, state.quantityOfAllPokemons, 12)
  }
)

Finally, like in other answer drop data from:最后,就像在其他答案中一样,从以下位置删除data

this.dataSource = new MatTableDataSource(pokemons);

This seems to work.这似乎有效。

Your forked STACKBLITZ你的分叉STACKBLITZ

You might want to tweak the loading property in your store, currently images appear with delay (at least for me), when fetching all individual data for pokemons.您可能想要调整商店中的loading属性,当前图像在获取宠物小精灵的所有单个数据时出现延迟(至少对我而言)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 “string”类型的参数不能分配给类型为“{[key:string]:any;}的参数 - Argument of type 'string' is not assignable to parameter of type '{ [key:string]:any;} 类型“ any []”的参数不能分配给类型“ A”的参数。 类型“ any []”中缺少属性“ a” - Argument of type 'any[]' is not assignable to parameter of type 'A'. Property 'a' is missing in type 'any[]' &#39;{ period: any; 类型的参数价格:任意; }&#39; 不可分配给类型为 &#39;MAInput&#39; 的参数 - Argument of type '{ period: any; prices: any; }' is not assignable to parameter of type 'MAInput' &#39;ReadableStream 类型的参数<any> &#39; 不可分配给类型为 &#39;ReadableStream&#39; 的参数 - Argument of type 'ReadableStream<any>' is not assignable to parameter of type 'ReadableStream' x 类型的参数不能分配给 '{ x: any; 类型的参数。 }' - Argument of type x is not assignable to parameter of type '{ x: any; }' typescript:类型&#39;any []&#39;的参数不能分配给&#39;[]&#39;类型的参数.ts(2345) - typescript : Argument of type 'any[]' is not assignable to parameter of type '[]'.ts(2345) '{验证器类型的参数:任何; }' 不可分配给“ValidatorFn”类型的参数 - Argument of type '{ validator: any; }' is not assignable to parameter of type 'ValidatorFn React Typescript:'{ [x: number]: any; 类型的参数 }' 不可分配给类型的参数 - React Typescript: Argument of type '{ [x: number]: any; }' is not assignable to parameter of type “事件”类型的参数不可分配给“CdkDragMove”类型的参数<any> &#39; - Argument of type 'Event' is not assignable to parameter of type 'CdkDragMove<any>' “any”类型的参数不可分配给“never”类型的参数 typescript 解决方案 - argument of type 'any' is not assignable to parameter of type 'never' typescript solution
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM