I'm fairly new to TypeScript and I'm running into an issue. I have a .ts
I'm using to store some helper functions. These functions are called via .call
so the proper this
is referenced. In that file, each this gives the following two errors:
'this' implicitly has type 'any' because it does not have a type annotation.
An outer value of 'this' is shadowed by this container.
Relevant section of the component file:
<script lang="ts">
import { defineComponent } from "vue";
import { deleteTodo, getId, setEditId, toggleDone } from "./App.helpers";
import EditTodoDialog from "./components/EditTodoDialog.vue";
import TodoForm from "./components/TodoForm.vue";
import TodoTable from "./components/TodoTable.vue";
export default defineComponent({
components: { EditTodoDialog, TodoForm, TodoTable },
data() {
return {
addTodoInputValue: "" as string,
editTodoId: "" as string,
editTodoInputValue: "" as string,
todoArr: [] as Array,
};
},
methods: {
addTodo() {
if (this.addTodoInputValue) {
const id = getId();
const newTodo = {
handleDelete: () => deleteTodo.call(this, id),
handleSetEditId: () => setEditId.call(this, id),
handleToggleDone: () => toggleDone.call(this, id),
id,
isDone: false,
task: this.addTodoInputValue,
};
this.todoArr.push(newTodo);
this.addTodoInputValue = "";
}
},
closeDialog() {
this.editTodoId = "";
},
updateTodo() {
if (this.editTodoInputValue) {
const targetIndex = this.todoArr.findIndex(
({ id }) => id === this.editTodoId
);
this.todoArr[targetIndex].task = this.editTodoInputValue;
this.editTodoId = "";
this.editTodoInputValue = "";
}
},
},
name: "App",
});
</script>
Helpers file:
export function deleteTodo(targetId: string) {
const targetIndex = this.todoArr.findIndex(
({ id }: { id: string }) => id === targetId
);
this.todoArr.splice(targetIndex, 1);
}
export function getId() {
return `${getRandomNumStr()}-${getRandomNumStr()}`;
}
export function getRandomNumStr() {
return Math.random().toString().slice(2);
}
export function setEditId(id: string) {
this.editTodoId = id;
}
export function toggleDone(targetId: string) {
const targetIndex = this.todoArr.findIndex(
({ id }: { id: string }) => id === targetId
);
const targetTodo = this.todoArr[targetIndex];
targetTodo.isDone = !targetTodo.isDone;
}
Here's the repo (it's small): https://github.com/colebillys19/vue-todo-typescript The file in question is App.helpers.ts
.
For additional context, I got the project up and running without TypeScript and everything works fine. That repo is here if you're interested: https://github.com/colebillys19/vue-todo
CodePudding user response:
Your helpers class is not declaring the functions on any object, so when you call deleteTodo
the only this
in scope is the current function, which means that this.todoArr
doesn't exist as it isn't declared in the function. Typescript is more object oriented than regular javascript and it doesn't understand throwing functions around in quite the same way.
You might try something like this:
export class Helpers {
public function deleteTodo(todoArr: Array<ToDo>, targetId: string): Array<ToDo> {
const targetIndex = todoArr.findIndex(
({ id }: { id: string }) => id === targetId
);
todoArr.splice(targetIndex, 1);
return todoArr;
}
// And so on
}
Then you would call it with this.todoArr = Helpers.deleteTodo(this.todoArr, 'banana')
and so on.
To me that feels a little clunky- if you're going to want to call deleteTodo
from a few different places, then I would think about how you structure things. I would probably have some kind of TodoService
that handles deletion, updates and so on and then call that from different components so there is a single point of responsibility. Alternatively you could also have a TodoHandler
class that includes those methods and have the types that need it inherit from it, so those methods and collections are automatically available. I use Typescript a lot but I haven't worked with Vue so I can't say what would be the most idiomatic approach in that respect.
Having functions to generate Ids and other commonly used simple functions in helper classes works great, but altering your data model is more structurally significant and probably belongs in its own place.