Issue
I want to use custom global declaration in NextJS
I have a NextJS project in which I have created a global prototype to String like below
utils.d.ts
export {}
declare global {
interface String {
/**
* Returns string after removing all html tags.
*/
stripHtml(): string
}
}
String.prototype.stripHtml = function (): string {
return this.replace(/(<([^>]+)>)/gi, '')
}
Then I've included utils.d.ts file in tsconfig.json like below
tsconfig.json
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"paths": {
"@/*": ["./*"]
},
"experimentalDecorators": true,
"emitDecoratorMetadata": true
},
"include": ["utils.d.ts", "next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}
Then I've used it inside my component Example.tsx like below
Exmaple.tsx
import React from 'react'
interface Props {
posts: Record<string, any>[]
}
const Example: React.FC<Props> = ({ posts }) => {
return (
<section>
<div className="container">
<div>
{posts.map((item, idx) => {
const post = item.attributes
const { title, content } = post
return (
<div key={`post-${idx}`}>
<div>
<h2>{title}</h2>
<p>{content.stripHtml()}</p>
</div>
</div>
)
})}
</div>
</div>
</section>
)
}
export default Example
Now VS Code is recognizing the declaration and not showing any red lines like before. Now when I'm running the project using dev command getting below error.
TypeError: content.stripHtml is not a function
at eval (webpack-internal:///./components/Example.tsx:37:58)
at Array.map (<anonymous>)
at Example (webpack-internal:///./components/Example.tsx:21:40)
at renderWithHooks (/Users/vickyvish/Projects/eweb-next/node_modules/react-dom/cjs/react-dom-server.browser.development.js:5658:16)
at renderIndeterminateComponent (/Users/vickyvish/Projects/eweb-next/node_modules/react-dom/cjs/react-dom-server.browser.development.js:5731:15)
at renderElement (/Users/vickyvish/Projects/eweb-next/node_modules/react-dom/cjs/react-dom-server.browser.development.js:5946:7)
at renderNodeDestructiveImpl (/Users/vickyvish/Projects/eweb-next/node_modules/react-dom/cjs/react-dom-server.browser.development.js:6104:11)
at renderNodeDestructive (/Users/vickyvish/Projects/eweb-next/node_modules/react-dom/cjs/react-dom-server.browser.development.js:6076:14)
at renderNode (/Users/vickyvish/Projects/eweb-next/node_modules/react-dom/cjs/react-dom-server.browser.development.js:6259:12)
at renderChildrenArray (/Users/vickyvish/Projects/eweb-next/node_modules/react-dom/cjs/react-dom-server.browser.development.js:6211:7)
at renderNodeDestructiveImpl (/Users/vickyvish/Projects/eweb-next/node_modules/react-dom/cjs/react-dom-server.browser.development.js:6141:7)
at renderNodeDestructive (/Users/vickyvish/Projects/eweb-next/node_modules/react-dom/cjs/react-dom-server.browser.development.js:6076:14)
at renderNode (/Users/vickyvish/Projects/eweb-next/node_modules/react-dom/cjs/react-dom-server.browser.development.js:6259:12)
at renderChildrenArray (/Users/vickyvish/Projects/eweb-next/node_modules/react-dom/cjs/react-dom-server.browser.development.js:6211:7)
at renderNodeDestructiveImpl (/Users/vickyvish/Projects/eweb-next/node_modules/react-dom/cjs/react-dom-server.browser.development.js:6141:7)
Solution
You did everything correct in sense of TypeScript, however the problem was that you did not extend the String prototype with the function stripHtml, hence the error: "stripHtml is not a function.".
The correct solution would be to declare the type in a utils.d.ts
file and extend String prototype in a separate file utils.ts
, then import it once at the top-level of the app.
The app's root layout.tsx
would be the most optimal place to import it, that way it is accessible in the whole the components tree.
Example:
File: utils.ts
import './utils.d'
String.prototype.stripHtml = function (): string {
return this.replace(/(<([^>]+)>)/gi, '')
}
File: utils.d.ts
export {}
declare global {
interface String {
/**
* Returns string after removing all html tags.
*/
stripHtml(): string
}
}
File: app/layout.tsx
import '@/utils'
Edit: P.s. This practice is usually called prototype pollution which is a bad practice, for reasons that I won't ramble on here as there are many articles explaining the reasoning of it. One suggestion would be to declare the util function in a module and import it only in files where it's needed.
Answered By - Develophir
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.