3

I have some code that takes a SP List item column (a news article tagged to one or more choice categories) and want to show that to users who have a user profile property with one or more categories they subscribe to (csv). When I display my news, I only want to show items that match what the user subscribes to.

I can run this TS online in an editor and it works (see snippet https://www.typescriptlang.org/play/index.html#src=Array.prototype.diff%20%3D%20function%20(arr2)%20%7B%0D%0Avar%20ret%20%3D%20%5B%5D%3B%0D%0A%20%20for%20(var%20i%20in%20this)%20%7B%0D%0A%20%20%20%20%20if%20(arr2.indexOf(this%5Bi%5D)%20%3E%20-1)%20%7B%0D%0A%20%20%20%20%20%20%20%20ret.push(this%5Bi%5D)%3B%0D%0A%20%20%20%20%20%20%7D%0D%0A%20%20%7D%0D%0A%20%20return%20ret%3B%0D%0A%7D%3B%0D%0Avar%20array1%20%3D%20%5B%22Panda%22%2C%20%22Zebra%22%2C%20%22Lion%22%2C%20%22Cat%22%2C%20%22Dog%22%2C%20%22Fish%22%2C%20%22whatever%22%2C%20%22Bird%22%5D%3B%0D%0Avar%20array2%20%3D%20%5B%22Panda%22%2C%20%22Cat%22%5D%3B%0D%0A%0D%0Aconsole.log(array1.diff(array2))%3B ) but cannot validate or build this code in my new SPFX web part using the latest Yeoman templates. It says (TS) property "diff" does not exist on type 'any[]'

Array.prototype.diff = function (arr2) {
var ret = [];
  for (var i in this) {
     if (arr2.indexOf(this[i]) > -1) {
        ret.push(this[i]);
      }
  }
  return ret;
};
var array1 = ["Panda", "Zebra", "Lion", "Cat", "Dog", "Fish", "whatever", "Bird"];
var array2 = ["Panda", "Cat"];

console.log(array1.diff(array2));

OOTB from Yeoman theres types es6-promise with es5 lib and targets.

How do I get diff to work? How can I see if es5 or es6 is "loaded" on my ts code page?

gulp package error:

PS C:\VS\ClientProject> gulp bundle --ship
Build target: SHIP
[13:41:22] Using gulpfile C:\VS\ClientProject\gulpfile.js
[13:41:22] Starting gulp
[13:41:22] Starting 'bundle'...
[13:41:22] Starting subtask 'configure-sp-build-rig'...
[13:41:22] Finished subtask 'configure-sp-build-rig' after 12 ms
[13:41:22] Starting subtask 'pre-copy'...
[13:41:22] Finished subtask 'pre-copy' after 14 ms
[13:41:22] Starting subtask 'copy-static-assets'...
[13:41:22] Starting subtask 'sass'...
[13:41:24] Finished subtask 'sass' after 1.54 s
[13:41:24] Starting subtask 'tslint'...
[13:41:25] Starting subtask 'typescript'...
[13:41:25] [typescript] TypeScript version: 2.4.2
[13:41:26] Finished subtask 'copy-static-assets' after 3.21 s
Warning: no-duplicate-case rule is deprecated. Replace your usage with the TSLint no-duplicate-switch-case rule.
Warning: valid-typeof rule is deprecated. Replace your usage with the TSLint typeof-compare rule.
[13:41:26] Warning - tslint - src\webparts\clientProject\clientProjectWebPart.ts(102,45): error no-function-expression: Use arrow function instead of function expression
[13:41:26] Warning - tslint - src\webparts\clientProject\clientProjectWebPart.ts(105,30): error no-function-expression: Use arrow function instead of function expression
[13:41:26] Warning - tslint - src\webparts\clientProject\clientProjectWebPart.ts(115,14): error no-function-expression: Use arrow function instead of function expression
[13:41:26] Warning - tslint - src\webparts\clientProject\clientProjectWebPart.ts(97,142): error no-shadowed-variable: Shadowed name: 'jQuery'
[13:41:26] Finished subtask 'tslint' after 2.44 s
[13:41:28] Error - typescript - src\webparts\clientProject\clientProjectWebPart.ts(137,20): error TS2339: Property 'diff' does not exist on type 'any[]'.
[13:41:28] Error - typescript - src\webparts\clientProject\clientProjectWebPart.ts(149,23): error TS2339: Property 'diff' does not exist on type 'string[]'.
[13:41:28] Error - 'typescript' sub task errored after 2.8 s
 TypeScript error(s) occurred.
[13:41:28] 'bundle' errored after 6.03 s
[13:41:28]
[13:41:29] ==================[ Finished ]==================
Warning - tslint - src/webparts/clientProject/clientProjectWebPart.ts(102,45): error no-function-expression: Use arrow function instead of function expression
Warning - tslint - src/webparts/clientProject/clientProjectWebPart.ts(105,30): error no-function-expression: Use arrow function instead of function expression
Warning - tslint - src/webparts/clientProject/clientProjectWebPart.ts(115,14): error no-function-expression: Use arrow function instead of function expression
Warning - tslint - src/webparts/clientProject/clientProjectWebPart.ts(97,142): error no-shadowed-variable: Shadowed name: 'jQuery'
Error - typescript - src/webparts/clientProject/clientProjectWebPart.ts(137,20): error TS2339: Property 'diff' does not exist on type 'any[]'.
Error - typescript - src/webparts/clientProject/clientProjectWebPart.ts(149,23): error TS2339: Property 'diff' does not exist on type 'string[]'.
Error - 'typescript' sub task errored after 2.8 s
 TypeScript error(s) occurred.
[13:41:29] Project r-net-homepage-news version: 0.0.1
[13:41:29] Build tools version: 3.2.7
[13:41:29] Node version: v6.10.3
[13:41:29] Total duration: 11 s
[13:41:29] Task warnings: 4
[13:41:29] Task errors: 3

tsconfig.json

{
  "compilerOptions": {
    "target": "es5",
    "forceConsistentCasingInFileNames": true,
    "module": "commonjs",
    "jsx": "react",
    "declaration": true,
    "sourceMap": true,
    "experimentalDecorators": true,
    "skipLibCheck": true,
    "typeRoots": [
      "./node_modules/@types",
      "./node_modules/@microsoft"
    ],
    "types": [
      "es6-promise",
      "webpack-env"
    ],
    "lib": [
      "es5",
      "dom",
      "es2015.collection"
    ]
  }
}

Thanks,

Eric Schrader

4

Since an interface in TypeScript is open ended this means that you can just add members to the interfaces declared in lib.d.ts and TypeScript will pick up on the additions. Note that you need to make these changes in a global module for these interfaces to get associated with lib.d.ts

Reference - Typescript lib.d.ts Deep dive

So, you can just declare an interface inside the global namespace and it will be picked up by typescript.

Modify your code as below:

Add this snippet before your webpart class.

declare global {
  interface Array<T> {
    diff(array: Array<T>);
  }
}

Array.prototype.diff = function (array) {
  var ret = [];
    for (var i in this) {
       if (array.indexOf(this[i]) > -1) {
          ret.push(this[i]);
        }
    }
    return ret;
};

And in your method, you can use it as below:

var array1 = ["Panda", "Zebra", "Lion", "Cat", "Dog", "Fish", "whatever", "Bird"];
var array2 = ["Panda", "Cat"];

console.log(array1.diff(array2));

So, your full code will look something like this (in your .ts file):

import { Version } from '@microsoft/sp-core-library';

//other import/export statements

declare global {
  interface Array<T> {
    diff(array: Array<T>);
  }
}

Array.prototype.diff = function (array) {
  var ret = [];
    for (var i in this) {
       if (array.indexOf(this[i]) > -1) {
          ret.push(this[i]);
        }
    }
    return ret;
};

export default class TestspfxWebPart extends BaseClientSideWebPart<ITestspfxWebPartProps> {
    public render(): void {
      //something to render

      var array1 = ["Panda", "Zebra", "Lion", "Cat", "Dog", "Fish", "whatever", "Bird"];
      var array2 = ["Panda", "Cat"];

      console.log(array1.diff(array2));
    }

}

Ideally, you can create another global.d.ts file and import it in your webpart.

  • Sorry to hijack the original question, but would this also be the 'best practice' method for adding an Array.prototype.find polyfill? developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… – Tracy Feb 16 '18 at 1:18
  • 1
    @Tracy - yes this is the way to go. As I mentioned in the answer, you can create another file and import it for re-usability. – Gautam Sheth Feb 16 '18 at 6:38
1

Also found that the @microsoft/sp-lodash-subset has an intersection method I can use. https://lodash.com/docs/4.17.4#intersection

import { escape, intersection  } from '@microsoft/sp-lodash-subset';
let array1 : any= ["Panda", "Zebra", "Lion", "Cat", "Dog", "Fish", "whatever", "Bird"];
let array2 : any = ["Panda", "Cat"];
intersection(array1, array2);
0

For now, I simplified the comparison to not use diff() but to use some() which is available in es5 or whatever is OOTB

var array1 = ["Panda", "Zebra", "Lion", "Cat", "Dog", "Fish", "whatever", "Bird"];
var array2 = ["Panda", "Cat"];

        function checkAvailability(arr, val) {
          return arr.some(function (arrVal) {
            return val === arrVal;
          });
        }
        for (let entry of array2) {
          if (checkAvailability(array1, entry)) {
            console.log(entry);
            //break, we have the first match which is all we need. Include this news article result or whatever logic needs to happen
          }
        }

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.